aws-cognito-srp 0.1.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a9d319dfe478786e4bda431aa7d660c10944737a7d66e95c8c253ab5ec75f691
4
- data.tar.gz: 3741cfe9072feea72cc50d5c41ed5f5111cf9f28df32eaeefdd223908e00e880
3
+ metadata.gz: 6000777b1471345bf83ef454e2147786b46c8960218729c0ef9b33d05bc08634
4
+ data.tar.gz: 5b28a08b3614d6dbe6f05a1bc25fd54200a8c90bb6fe8e3a24f97e4afc1bbe80
5
5
  SHA512:
6
- metadata.gz: f6f713236d8e76dd635dda2a2437393d7a2b0b009e1f148bf138e53791cf0a1d90e077ffedc7a880f0caf878ab4d493ace2194a43d84b5c96bffcab8c07c5ba2
7
- data.tar.gz: d28cb221df9702987bf37c1f7b1c4fd12af4b74182834435e8ca7833ffc3ad7ba772b3564c883d26d069af167abfa955bc42703d622a794762050617c6077eaa
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
- ### [0.1.0] - 2021-09-17
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
+ [![Gem Version](https://badge.fury.io/rb/aws-cognito-srp.svg?style=flat)](https://rubygems.org/gems/aws-cognito-srp)
4
+ ![CI](https://github.com/beezwax/aws-cognito-srp-ruby/workflows/CI/badge.svg)
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: "ap-southeast-2")
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/pilaf/aws-cognito-srp-ruby
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.
@@ -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/pilaf/aws-cognito-srp-ruby"
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Aws
4
4
  class CognitoSrp
5
- VERSION = "0.1.0"
5
+ VERSION = "0.4.0"
6
6
  end
7
7
  end
@@ -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
- raise unless init_auth_response.challenge_name == PASSWORD_VERIFIER
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
- raise "new password required" if auth_response.challenge_name == NEW_PASSWORD_REQUIRED
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
- if u_value == 0
114
- raise "U cannot be zero."
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
- hkdf = compute_hkdf(hex_to_bytes(pad_hex(s_value)), hex_to_bytes(pad_hex(long_to_hex(u_value))))
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('sha256'), hkdf, msg)
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
- "TIMESTAMP" => timestamp,
144
- "USERNAME" => user_id_for_srp,
145
- "PASSWORD_CLAIM_SECRET_BLOCK" => secret_block_b64,
146
- "PASSWORD_CLAIM_SIGNATURE" => signature_string
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
- random_hex = bytes_to_hex(SecureRandom.bytes(nbytes))
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 = if long_int.is_a?(String)
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('sha256'), salt, ikm)
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('sha256'), prk, info_bits_update)
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.1.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-09-17 00:00:00.000000000 Z
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/main.yml"
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/pilaf/aws-cognito-srp-ruby
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.2.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
@@ -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