aws-cognito-srp 0.1.0 → 0.4.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/.github/workflows/ci.yml +26 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +13 -1
- data/README.md +26 -3
- data/aws-cognito-srp.gemspec +3 -1
- data/lib/aws/cognito_srp/errors.rb +12 -0
- data/lib/aws/cognito_srp/version.rb +1 -1
- data/lib/aws/cognito_srp.rb +71 -33
- metadata +35 -5
- data/.github/workflows/main.yml +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6000777b1471345bf83ef454e2147786b46c8960218729c0ef9b33d05bc08634
|
4
|
+
data.tar.gz: 5b28a08b3614d6dbe6f05a1bc25fd54200a8c90bb6fe8e3a24f97e4afc1bbe80
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d1e507ab4e5a8ce39647a2699ad1bac52a62352c6b2a04d2eb47b12954ae8c8a1f86f26c457583c13f84200064620cbf938381894d302a457b7a2c0468f5f26e
|
7
|
+
data.tar.gz: 3714f171b5527ed457d2c05e0ff5aece5f96d572e9f48e4fa6412b9cedad85d69ac54432b7e719f7afe0406aa7d135562b0f7446d705d0a4a494f22c48a45bd4
|
@@ -0,0 +1,26 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on: [push,pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
strategy:
|
8
|
+
fail-fast: false
|
9
|
+
matrix:
|
10
|
+
ruby: [2.3, 2.4, 2.5, 2.6, 2.7, '3.0']
|
11
|
+
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
|
14
|
+
name: Test against Ruby ${{ matrix.ruby }}
|
15
|
+
|
16
|
+
steps:
|
17
|
+
- uses: actions/checkout@v2
|
18
|
+
- name: Set up Ruby
|
19
|
+
uses: ruby/setup-ruby@v1
|
20
|
+
with:
|
21
|
+
ruby-version: ${{ matrix.ruby }}
|
22
|
+
bundler-cache: true
|
23
|
+
- name: Install dependencies
|
24
|
+
run: bundle install --jobs 4 --retry 3
|
25
|
+
- name: Run specs
|
26
|
+
run: bundle exec rspec spec --backtrace
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--require spec_helper
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
## Changelog for aws-cognito-srp-ruby
|
2
2
|
|
3
|
-
###
|
3
|
+
### 0.4.0 (October 1, 2021)
|
4
|
+
|
5
|
+
* Added `refresh_tokens` method
|
6
|
+
|
7
|
+
### 0.3.0 (September 29, 2021)
|
8
|
+
|
9
|
+
* Added support for Ruby 2.4 and 2.3
|
10
|
+
|
11
|
+
### 0.2.0 (September 20, 2021)
|
12
|
+
|
13
|
+
* Added custom exception classes and better error messages
|
14
|
+
|
15
|
+
### 0.1.0 (Septembre 17, 2021)
|
4
16
|
|
5
17
|
* Initial release
|
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Aws::CognitoSrp for Ruby
|
2
2
|
|
3
|
+
[](https://rubygems.org/gems/aws-cognito-srp)
|
4
|
+

|
5
|
+
|
3
6
|
An unofficial Ruby library implementing
|
4
7
|
[AWS Cognito's SRP authentication flow](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#Using-SRP-password-verification-in-custom-authentication-flow).
|
5
8
|
|
@@ -26,12 +29,25 @@ aws_srp = Aws::CognitoSrp.new(
|
|
26
29
|
password: "password",
|
27
30
|
pool_id: "pool-id",
|
28
31
|
client_id: "client-id",
|
29
|
-
aws_client: Aws::CognitoIdentityProvider::Client.new(region: "
|
32
|
+
aws_client: Aws::CognitoIdentityProvider::Client.new(region: "aws-region")
|
30
33
|
)
|
31
34
|
|
32
|
-
aws_srp.authenticate
|
35
|
+
resp = aws_srp.authenticate
|
36
|
+
|
37
|
+
# Read tokens
|
38
|
+
resp.id_token
|
39
|
+
resp.access_token
|
40
|
+
resp.refresh_token
|
41
|
+
|
42
|
+
# A few hours later ... ⌛️
|
43
|
+
|
44
|
+
new_tokens = aws_srp.refresh_tokens(resp.refresh_token)
|
33
45
|
```
|
34
46
|
|
47
|
+
## Supported rubies
|
48
|
+
|
49
|
+
This gem is tested against and supports Ruby 2.3, 2.4, 2.5, 2.6, 2.7 and 3.0.
|
50
|
+
|
35
51
|
## Development
|
36
52
|
|
37
53
|
After checking out the repo, run `bin/setup` to install dependencies. You can
|
@@ -47,4 +63,11 @@ git commits and the created tag, and push the `.gem` file to
|
|
47
63
|
## Contributing
|
48
64
|
|
49
65
|
Bug reports and pull requests are welcome on GitHub at
|
50
|
-
https://github.com/
|
66
|
+
https://github.com/beezwax/aws-cognito-srp-ruby
|
67
|
+
|
68
|
+
## Disclaimer
|
69
|
+
|
70
|
+
This project is not sponsored by or otherwise affiliated with Amazon Web
|
71
|
+
Services, Inc., an Amazon.com, Inc. subsidiary. AWS and Amazon Cognito are
|
72
|
+
trademarks of Amazon.com, Inc., or its affiliates in the United States and/or
|
73
|
+
other countries.
|
data/aws-cognito-srp.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
|
11
11
|
spec.summary = "AWS Cognito SRP auth for Ruby"
|
12
12
|
spec.description = "Unofficial Ruby library implementing AWS Cognito's SRP authentication flow"
|
13
|
-
spec.homepage = "https://github.com/
|
13
|
+
spec.homepage = "https://github.com/beezwax/aws-cognito-srp-ruby"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
16
|
# Specify which files should be added to the gem when it is released.
|
@@ -25,6 +25,8 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.add_development_dependency "bundler", "~> 2.2.0"
|
26
26
|
spec.add_development_dependency "rake", "~> 13.0"
|
27
27
|
spec.add_development_dependency "ox", "~> 2.14.0"
|
28
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
29
|
+
spec.add_development_dependency "pry"
|
28
30
|
|
29
31
|
# For more information and examples about making a new gem, checkout our
|
30
32
|
# guide at: https://bundler.io/guides/creating_gem.html
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "aws/cognito_srp/errors"
|
4
|
+
|
5
|
+
module Aws
|
6
|
+
class CognitoSrp
|
7
|
+
class Error < ::RuntimeError; end
|
8
|
+
class UnexpectedChallenge < Error; end
|
9
|
+
class NewPasswordRequired < Error; end
|
10
|
+
class ValueError < Error; end
|
11
|
+
end
|
12
|
+
end
|
data/lib/aws/cognito_srp.rb
CHANGED
@@ -1,10 +1,41 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "aws-sdk-cognitoidentityprovider"
|
4
|
-
require "aws/cognito_srp/version"
|
5
4
|
|
6
5
|
require "openssl"
|
7
6
|
require "digest"
|
7
|
+
require "securerandom"
|
8
|
+
require "base64"
|
9
|
+
|
10
|
+
require "aws/cognito_srp/version"
|
11
|
+
require "aws/cognito_srp/errors"
|
12
|
+
|
13
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.5")
|
14
|
+
module IntegerWithPow
|
15
|
+
refine Integer do
|
16
|
+
# Integer#pow was introduced in Ruby 2.5
|
17
|
+
# Use OpenSSL's modular exponentiation in older Rubies
|
18
|
+
def pow(b, m)
|
19
|
+
self.to_bn.mod_exp(b, m).to_i
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
using IntegerWithPow
|
25
|
+
end
|
26
|
+
|
27
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.4")
|
28
|
+
module StringWithUnpack1
|
29
|
+
refine String do
|
30
|
+
# String#unpack1 was introduced in Ruby 2.4
|
31
|
+
def unpack1(fmt)
|
32
|
+
unpack(fmt)[0]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
using StringWithUnpack1
|
38
|
+
end
|
8
39
|
|
9
40
|
module Aws
|
10
41
|
# Client for AWS Cognito Identity Provider using Secure Remote Password (SRP).
|
@@ -28,9 +59,10 @@ module Aws
|
|
28
59
|
# aws_srp.authenticate
|
29
60
|
#
|
30
61
|
class CognitoSrp
|
31
|
-
USER_SRP_AUTH = "USER_SRP_AUTH"
|
32
|
-
PASSWORD_VERIFIER = "PASSWORD_VERIFIER"
|
33
62
|
NEW_PASSWORD_REQUIRED = "NEW_PASSWORD_REQUIRED"
|
63
|
+
PASSWORD_VERIFIER = "PASSWORD_VERIFIER"
|
64
|
+
REFRESH_TOKEN = "REFRESH_TOKEN"
|
65
|
+
USER_SRP_AUTH = "USER_SRP_AUTH"
|
34
66
|
|
35
67
|
N_HEX = %w(
|
36
68
|
FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08
|
@@ -77,7 +109,9 @@ module Aws
|
|
77
109
|
}
|
78
110
|
)
|
79
111
|
|
80
|
-
|
112
|
+
unless init_auth_response.challenge_name == PASSWORD_VERIFIER
|
113
|
+
raise UnexpectedChallenge, "Expected Cognito to respond with a #{PASSWORD_VERIFIER} challenge, got #{init_auth_response.challenge_name} instead"
|
114
|
+
end
|
81
115
|
|
82
116
|
challenge_response = process_challenge(init_auth_response.challenge_parameters)
|
83
117
|
|
@@ -87,11 +121,26 @@ module Aws
|
|
87
121
|
challenge_responses: challenge_response
|
88
122
|
)
|
89
123
|
|
90
|
-
|
124
|
+
if auth_response.challenge_name == NEW_PASSWORD_REQUIRED
|
125
|
+
raise NewPasswordRequired, "Cognito responded to password verifier with a #{NEW_PASSWORD_REQUIRED} challenge"
|
126
|
+
end
|
91
127
|
|
92
128
|
auth_response.authentication_result
|
93
129
|
end
|
94
130
|
|
131
|
+
def refresh_tokens(refresh_token)
|
132
|
+
resp = @aws_client.initiate_auth(
|
133
|
+
client_id: @client_id,
|
134
|
+
auth_flow: REFRESH_TOKEN,
|
135
|
+
auth_parameters: {
|
136
|
+
REFRESH_TOKEN: refresh_token
|
137
|
+
}
|
138
|
+
)
|
139
|
+
|
140
|
+
resp.authentication_result
|
141
|
+
end
|
142
|
+
alias_method :refresh, :refresh_tokens
|
143
|
+
|
95
144
|
private
|
96
145
|
|
97
146
|
def generate_random_small_a
|
@@ -101,18 +150,14 @@ module Aws
|
|
101
150
|
|
102
151
|
def calculate_a
|
103
152
|
big_a = @g.pow(@small_a_value, @big_n)
|
104
|
-
if big_a % @big_n == 0
|
105
|
-
raise "Safety check for A failed"
|
106
|
-
end
|
107
|
-
|
153
|
+
raise ValueError, "Safety check for A failed" if big_a % @big_n == 0
|
108
154
|
big_a
|
109
155
|
end
|
110
156
|
|
111
157
|
def get_password_authentication_key(username, password, server_b_value, salt)
|
112
158
|
u_value = calculate_u(@large_a_value, server_b_value)
|
113
|
-
|
114
|
-
|
115
|
-
end
|
159
|
+
|
160
|
+
raise ValueError, "U cannot be zero" if u_value == 0
|
116
161
|
|
117
162
|
username_password = "#{@pool_id.split("_")[1]}#{username}:#{password}"
|
118
163
|
username_password_hash = hash_sha256(username_password)
|
@@ -121,8 +166,7 @@ module Aws
|
|
121
166
|
g_mod_pow_xn = @g.pow(x_value, @big_n)
|
122
167
|
int_value2 = server_b_value - @k * g_mod_pow_xn
|
123
168
|
s_value = int_value2.pow(@small_a_value + u_value * x_value, @big_n)
|
124
|
-
|
125
|
-
hkdf
|
169
|
+
compute_hkdf(hex_to_bytes(pad_hex(s_value)), hex_to_bytes(pad_hex(long_to_hex(u_value))))
|
126
170
|
end
|
127
171
|
|
128
172
|
def process_challenge(challenge_parameters)
|
@@ -131,24 +175,24 @@ module Aws
|
|
131
175
|
srp_b_hex = challenge_parameters.fetch("SRP_B")
|
132
176
|
secret_block_b64 = challenge_parameters.fetch("SECRET_BLOCK")
|
133
177
|
|
134
|
-
timestamp = Time.now.utc.strftime("%a %b %-d %H:%M:%S %Z %Y")
|
178
|
+
timestamp = ::Time.now.utc.strftime("%a %b %-d %H:%M:%S %Z %Y")
|
135
179
|
|
136
180
|
hkdf = get_password_authentication_key(user_id_for_srp, @password, srp_b_hex.to_i(16), salt_hex)
|
137
|
-
secret_block_bytes = Base64.strict_decode64(secret_block_b64)
|
181
|
+
secret_block_bytes = ::Base64.strict_decode64(secret_block_b64)
|
138
182
|
msg = @pool_id.split("_")[1] + user_id_for_srp + secret_block_bytes + timestamp
|
139
|
-
hmac_digest = OpenSSL::HMAC.digest(OpenSSL::Digest.new
|
140
|
-
signature_string = Base64.strict_encode64(hmac_digest).force_encoding('utf-8')
|
183
|
+
hmac_digest = ::OpenSSL::HMAC.digest(::OpenSSL::Digest::SHA256.new, hkdf, msg)
|
184
|
+
signature_string = ::Base64.strict_encode64(hmac_digest).force_encoding('utf-8')
|
141
185
|
|
142
186
|
{
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
187
|
+
TIMESTAMP: timestamp,
|
188
|
+
USERNAME: user_id_for_srp,
|
189
|
+
PASSWORD_CLAIM_SECRET_BLOCK: secret_block_b64,
|
190
|
+
PASSWORD_CLAIM_SIGNATURE: signature_string
|
147
191
|
}
|
148
192
|
end
|
149
193
|
|
150
194
|
def hash_sha256(buf)
|
151
|
-
Digest::SHA256.hexdigest(buf)
|
195
|
+
::Digest::SHA256.hexdigest(buf)
|
152
196
|
end
|
153
197
|
|
154
198
|
def hex_hash(hex_string)
|
@@ -172,16 +216,11 @@ module Aws
|
|
172
216
|
end
|
173
217
|
|
174
218
|
def get_random(nbytes)
|
175
|
-
|
176
|
-
hex_to_long(random_hex)
|
219
|
+
hex_to_long(bytes_to_hex(::SecureRandom.gen_random(nbytes)))
|
177
220
|
end
|
178
221
|
|
179
222
|
def pad_hex(long_int)
|
180
|
-
hash_str =
|
181
|
-
long_int
|
182
|
-
else
|
183
|
-
long_to_hex(long_int)
|
184
|
-
end
|
223
|
+
hash_str = long_int.is_a?(::String) ? long_int : long_to_hex(long_int)
|
185
224
|
|
186
225
|
if hash_str.size % 2 == 1
|
187
226
|
hash_str = "0#{hash_str}"
|
@@ -193,9 +232,9 @@ module Aws
|
|
193
232
|
end
|
194
233
|
|
195
234
|
def compute_hkdf(ikm, salt)
|
196
|
-
prk = OpenSSL::HMAC.digest(OpenSSL::Digest.new
|
235
|
+
prk = ::OpenSSL::HMAC.digest(::OpenSSL::Digest::SHA256.new, salt, ikm)
|
197
236
|
info_bits_update = INFO_BITS + 1.chr.force_encoding('utf-8')
|
198
|
-
hmac_hash = OpenSSL::HMAC.digest(OpenSSL::Digest.new
|
237
|
+
hmac_hash = ::OpenSSL::HMAC.digest(::OpenSSL::Digest::SHA256.new, prk, info_bits_update)
|
199
238
|
hmac_hash[0, 16]
|
200
239
|
end
|
201
240
|
|
@@ -205,4 +244,3 @@ module Aws
|
|
205
244
|
end
|
206
245
|
end
|
207
246
|
end
|
208
|
-
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws-cognito-srp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Viney
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2021-
|
13
|
+
date: 2021-10-01 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: aws-sdk-cognitoidentityprovider
|
@@ -68,6 +68,34 @@ dependencies:
|
|
68
68
|
- - "~>"
|
69
69
|
- !ruby/object:Gem::Version
|
70
70
|
version: 2.14.0
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: rspec
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - "~>"
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '3.0'
|
78
|
+
type: :development
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - "~>"
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '3.0'
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: pry
|
87
|
+
requirement: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
type: :development
|
93
|
+
prerelease: false
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
71
99
|
description: Unofficial Ruby library implementing AWS Cognito's SRP authentication
|
72
100
|
flow
|
73
101
|
email:
|
@@ -76,8 +104,9 @@ executables: []
|
|
76
104
|
extensions: []
|
77
105
|
extra_rdoc_files: []
|
78
106
|
files:
|
79
|
-
- ".github/workflows/
|
107
|
+
- ".github/workflows/ci.yml"
|
80
108
|
- ".gitignore"
|
109
|
+
- ".rspec"
|
81
110
|
- CHANGELOG.md
|
82
111
|
- Gemfile
|
83
112
|
- LICENSE
|
@@ -88,9 +117,10 @@ files:
|
|
88
117
|
- bin/setup
|
89
118
|
- lib/aws-cognito-srp.rb
|
90
119
|
- lib/aws/cognito_srp.rb
|
120
|
+
- lib/aws/cognito_srp/errors.rb
|
91
121
|
- lib/aws/cognito_srp/version.rb
|
92
122
|
- lib/aws_cognito_srp.rb
|
93
|
-
homepage: https://github.com/
|
123
|
+
homepage: https://github.com/beezwax/aws-cognito-srp-ruby
|
94
124
|
licenses:
|
95
125
|
- MIT
|
96
126
|
metadata: {}
|
@@ -109,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
139
|
- !ruby/object:Gem::Version
|
110
140
|
version: '0'
|
111
141
|
requirements: []
|
112
|
-
rubygems_version: 3.
|
142
|
+
rubygems_version: 3.0.6
|
113
143
|
signing_key:
|
114
144
|
specification_version: 4
|
115
145
|
summary: AWS Cognito SRP auth for Ruby
|
data/.github/workflows/main.yml
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
name: Ruby
|
2
|
-
|
3
|
-
on: [push,pull_request]
|
4
|
-
|
5
|
-
jobs:
|
6
|
-
build:
|
7
|
-
runs-on: ubuntu-latest
|
8
|
-
steps:
|
9
|
-
- uses: actions/checkout@v2
|
10
|
-
- name: Set up Ruby
|
11
|
-
uses: ruby/setup-ruby@v1
|
12
|
-
with:
|
13
|
-
ruby-version: 3.0.0
|
14
|
-
bundler-cache: true
|
15
|
-
- name: Run the default task
|
16
|
-
run: bundle exec rake
|