soar_authentication_token 0.1.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cba64c87af18ce0cacb4333430c2056b2a8dbf4d
4
- data.tar.gz: 2b78253b2ce7ed01e483075950e81400c8d7435b
3
+ metadata.gz: 87964e7ea8211a562a63c243129746ca015c41f0
4
+ data.tar.gz: 9391628582b905df4d720f559bf787cdc1a46eaa
5
5
  SHA512:
6
- metadata.gz: 98fabb13ee0409d95199d7eceb98a1eed2af9c0f0b4a506e6e883ed9f762d488bdef6a5e786cac824f78a1437af3f32cd4b587e10a7ca1819e3a2d896a3512e5
7
- data.tar.gz: ec3ec0e4f402d2effabe925dfbefe3e7b7413eb0462cd8e6b3765386828d40d690f95a21965241f6fd14c0e9f2d7b4bbb9bc8134d9eac7874358057cad1de56b
6
+ metadata.gz: ac01a6c65000634dfa674bf4fdee98dd943739e2b12626de27ed57750f44b8daf94d87c828d13f6592bcf62991dc46d190502d5939b1079bd6e3a74a228807a2
7
+ data.tar.gz: 287ca8ee2cf219bea7a132a8c41e18d5c33427fa99a1c01df1a187ee2928c3e5d394e9247d34bb8daea36b1329852540c6af00bda25c3a2204e7de1e92ae3000
data/.gitmodules ADDED
@@ -0,0 +1,8 @@
1
+ [submodule "authentication-token-generator-service"]
2
+ path = authentication-token-generator-service
3
+ url = git@gitlab.host-h.net:hetznerZA/authentication-token-generator-service.git
4
+ branch = master
5
+ [submodule "authentication-token-validator-service"]
6
+ path = authentication-token-validator-service
7
+ url = git@gitlab.host-h.net:hetznerZA/authentication-token-validator-service.git
8
+ branch = master
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
1
  # A sample Gemfile
2
2
  source "https://rubygems.org"
3
+ source 'http://gems.hetzner.co.za'
3
4
 
4
5
  gemspec
data/docker-compose.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  version: '2.0'
2
2
  services:
3
3
  soar-authentication-token:
4
- command: /bin/bash -c 'sleep 10; bundle exec rspec -cfd spec'
4
+ command: /bin/bash -c 'sleep 5; bundle update; bundle exec rspec -cfd spec'
5
5
  build: .
6
6
  image: soar-authentication-token
7
7
  volumes:
@@ -10,22 +10,22 @@ services:
10
10
  - authentication-token-generator-service
11
11
  - authentication-token-validator-service
12
12
  authentication-token-generator-service:
13
- build: ../authentication-token-generator-service
13
+ build: authentication-token-generator-service
14
14
  image: authentication-token-generator-service
15
15
  expose:
16
16
  - "9393"
17
17
  volumes:
18
- - ../authentication-token-generator-service:/usr/local/src/
18
+ - ./authentication-token-generator-service:/usr/local/src/
19
19
  environment:
20
20
  - RACK_ENV=development
21
- - ENVIRONMENT_FILE=environment_local.yml
21
+ - ENVIRONMENT_FILE=environment_local_ecosystem.yml
22
22
  authentication-token-validator-service:
23
- build: ../authentication-token-validator-service
23
+ build: authentication-token-validator-service
24
24
  image: authentication-token-validator-service
25
25
  expose:
26
26
  - "9393"
27
27
  volumes:
28
- - ../authentication-token-validator-service:/usr/local/src/
28
+ - ./authentication-token-validator-service:/usr/local/src/
29
29
  environment:
30
30
  - RACK_ENV=development
31
- - ENVIRONMENT_FILE=environment_local.yml
31
+ - ENVIRONMENT_FILE=environment_local_ecosystem.yml
@@ -10,9 +10,10 @@ module SoarAuthenticationToken
10
10
  def call(env)
11
11
  request = Rack::Request.new env
12
12
  session, params = request.session, request.params
13
- valid, authenticated_identifier = validate_and_resolve_token(request.env['HTTP_AUTHORIZATION'],params['flow_identifier'])
13
+ valid, token_meta = validate_and_resolve_token(request.env['HTTP_AUTHORIZATION'],params['flow_identifier'])
14
14
  if valid
15
- session['user'] = authenticated_identifier
15
+ session['user'] = token_meta['authenticated_identifier']
16
+ session['auth_token_meta'] = token_meta
16
17
  @app.call env
17
18
  else
18
19
  [401, {"Content-Type" => "text/html"}, ["401 - Not authenticated"]]
@@ -9,6 +9,7 @@ require 'json'
9
9
  module SoarAuthenticationToken
10
10
  class TokenGenerator
11
11
  DEFAULT_CONFIGURATION = {
12
+ 'expiry' => 604800 #a days worth of seconds
12
13
  } unless defined? DEFAULT_CONFIGURATION; DEFAULT_CONFIGURATION.freeze
13
14
 
14
15
  def initialize(configuration)
@@ -17,6 +18,10 @@ module SoarAuthenticationToken
17
18
  @private_key = OpenSSL::PKey::EC.new(@configuration['private_key'])
18
19
  end
19
20
 
21
+ def inject_store_provider(store_provider)
22
+ @store_provider = store_provider
23
+ end
24
+
20
25
  def generate(authenticated_identifier:, flow_identifier: nil)
21
26
  return generate_locally(authenticated_identifier) if 'local' == @configuration['mode']
22
27
  return generate_remotely(authenticated_identifier,flow_identifier)
@@ -25,7 +30,7 @@ module SoarAuthenticationToken
25
30
  private
26
31
 
27
32
  def generate_locally(authenticated_identifier)
28
- encode(payload(authenticated_identifier))
33
+ encode(meta(authenticated_identifier))
29
34
  end
30
35
 
31
36
  def generate_remotely(authenticated_identifier,flow_identifier)
@@ -49,15 +54,17 @@ module SoarAuthenticationToken
49
54
  body['data']['token']
50
55
  end
51
56
 
52
- def payload(authenticated_identifier)
57
+ def meta(authenticated_identifier)
58
+ current_time = Time.now
53
59
  { 'authenticated_identifier' => authenticated_identifier,
54
- 'issue_time' => Time.now.utc.iso8601(3),
55
- 'nounce' => SecureRandom.hex(32)
60
+ 'token_issue_time' => current_time.utc.iso8601(3),
61
+ 'token_expiry_time' => (current_time + @configuration['expiry']).utc.iso8601(3),
62
+ 'token_identifier' => SecureRandom.hex(32)
56
63
  }
57
64
  end
58
65
 
59
- def encode(payload)
60
- JWT.encode(payload, @private_key, 'ES512')
66
+ def encode(meta)
67
+ JWT.encode(meta, @private_key, 'ES512')
61
68
  end
62
69
 
63
70
  def validate_configuration
@@ -67,6 +74,8 @@ module SoarAuthenticationToken
67
74
  raise "'generator-url' must be configured in remote mode" if @configuration['generator-url'].nil?
68
75
  else
69
76
  raise "'private_key' must be configured in local mode" unless @configuration['private_key']
77
+ raise "'expiry' must be configured in local mode" unless @configuration['expiry']
78
+ raise "'expiry' must be an integer" unless Integer(@configuration['expiry'])
70
79
  end
71
80
  end
72
81
 
@@ -74,5 +83,13 @@ module SoarAuthenticationToken
74
83
  configuration = {} unless configuration
75
84
  Hash.deep_merge(DEFAULT_CONFIGURATION,configuration)
76
85
  end
86
+
87
+ def add_token_to_store?(meta)
88
+ @store_provider.add(
89
+ token_identifier: meta['token_identifier'],
90
+ authenticated_identifier: meta['authenticated_identifier'],
91
+ token_issue_time: meta['token_issue_time'],
92
+ token_expiry_time: meta['token_expiry_time'])
93
+ end
77
94
  end
78
95
  end
@@ -4,7 +4,7 @@ require 'jwt'
4
4
  module SoarAuthenticationToken
5
5
  class TokenValidator
6
6
  DEFAULT_CONFIGURATION = {
7
- 'expiry' => 604800 #a days worth of seconds
7
+ 'expiry' => 604800 #a days worth of seconds
8
8
  } unless defined? DEFAULT_CONFIGURATION; DEFAULT_CONFIGURATION.freeze
9
9
 
10
10
  def initialize(configuration)
@@ -14,21 +14,45 @@ module SoarAuthenticationToken
14
14
  @public_key.private_key = nil
15
15
  end
16
16
 
17
+ def inject_store_provider(store_provider)
18
+ @store_provider = store_provider
19
+ end
20
+
17
21
  def validate(authentication_token:,flow_identifier: nil)
18
22
  return validate_locally(authentication_token) if 'local' == @configuration['mode']
19
23
  return validate_remotely(authentication_token,flow_identifier)
20
24
  end
21
25
 
26
+ def token(authentication_token:,flow_identifier: nil)
27
+ return validate_locally(authentication_token) if 'local' == @configuration['mode']
28
+ return validate_remotely(authentication_token,flow_identifier)
29
+ end
30
+
22
31
  private
23
32
 
24
33
  def validate_locally(authentication_token)
25
- decoded_token_payload = decode(authentication_token)
26
- return [false, nil] if expired?(decoded_token_payload[0]['issue_time'])
27
- [true, decoded_token_payload[0]['authenticated_identifier']]
34
+ meta = token_meta(authentication_token)
35
+ return [false, nil] if token_expired?(meta)
36
+ return [false, nil] if token_exist_in_store?(meta)
37
+ [true, meta]
28
38
  rescue JWT::VerificationError, JWT::DecodeError
29
39
  [false, nil]
30
40
  end
31
41
 
42
+ def token_meta(authentication_token)
43
+ decoded_token_payload = decode(authentication_token)
44
+ {
45
+ 'authenticated_identifier' => decoded_token_payload[0]['authenticated_identifier'],
46
+ 'token_issue_time' => decoded_token_payload[0]['token_issue_time'],
47
+ 'token_expiry_time' => decoded_token_payload[0]['token_expiry_time'],
48
+ 'token_age' => token_age(decoded_token_payload[0]['token_issue_time'])
49
+ }
50
+ end
51
+
52
+ def token_age(token_issue_time)
53
+ Time.now - Time.parse(token_issue_time)
54
+ end
55
+
32
56
  def validate_remotely(authentication_token,flow_identifier)
33
57
  uri = URI.parse(@configuration['validator-url'])
34
58
 
@@ -75,8 +99,16 @@ module SoarAuthenticationToken
75
99
  JWT.decode(authentication_token, @public_key, true, { :algorithm => 'ES512' })
76
100
  end
77
101
 
78
- def expired?(issue_time)
79
- (Time.parse(issue_time) + @configuration['expiry']) < Time.now
102
+ def token_expired?(meta)
103
+ Time.parse(meta['token_expiry_time']) < Time.now
104
+ end
105
+
106
+ def token_exist_in_store?(meta)
107
+ @store_provider.token_exist?(
108
+ token_identifier: meta['token_identifier'],
109
+ authenticated_identifier: meta['authenticated_identifier'],
110
+ token_issue_time: meta['token_issue_time'],
111
+ token_expiry_time: meta['token_expiry_time'])
80
112
  end
81
113
  end
82
114
  end
@@ -1,3 +1,3 @@
1
1
  module SoarAuthenticationToken
2
- VERSION = '0.1.0'
2
+ VERSION = '1.0.0'
3
3
  end
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.add_dependency 'soar_xt', '~> 0.0.3'
23
23
  spec.add_dependency 'jwt', '~> 1.5', '>= 1.5.6'
24
24
  spec.add_dependency "rack", '~> 1.6', '>= 1.6.4'
25
+ spec.add_dependency 'auth_token_store_provider', '~> 1.0.0'
25
26
 
26
27
  spec.add_development_dependency 'pry', '~> 0'
27
28
  spec.add_development_dependency 'bundler', '~> 1.3'
@@ -5,7 +5,17 @@ require 'rack/test'
5
5
  describe SoarAuthenticationToken::RackMiddleware do
6
6
  include Rack::Test::Methods
7
7
 
8
- def create_token_generator
8
+ def create_valid_token_generator
9
+ keypair_generator = SoarAuthenticationToken::KeypairGenerator.new
10
+ private_key, public_key = keypair_generator.generate
11
+ configuration = {
12
+ 'mode' => 'remote',
13
+ 'generator-url' => 'http://authentication-token-generator-service:9393/generate'
14
+ }
15
+ [ SoarAuthenticationToken::TokenGenerator.new(configuration), private_key, public_key ]
16
+ end
17
+
18
+ def create_invalid_token_generator
9
19
  keypair_generator = SoarAuthenticationToken::KeypairGenerator.new
10
20
  private_key, public_key = keypair_generator.generate
11
21
  configuration = {
@@ -17,8 +27,8 @@ describe SoarAuthenticationToken::RackMiddleware do
17
27
  end
18
28
 
19
29
  before :all do
20
- @local_valid_generator, @valid_private_key, @valid_public_key = create_token_generator
21
- @local_invalid_generator, @imvalid_private_key, @invalid_public_key = create_token_generator
30
+ @local_valid_generator, @valid_private_key, @valid_public_key = create_valid_token_generator
31
+ @local_invalid_generator, @imvalid_private_key, @invalid_public_key = create_invalid_token_generator
22
32
  end
23
33
 
24
34
  before :each do
@@ -27,7 +37,11 @@ describe SoarAuthenticationToken::RackMiddleware do
27
37
  session = request.session
28
38
  [200, {"Content-Type"=>"text/html"}, ["tested with authenticated user #{session['user']}"] ]
29
39
  end
30
- @iut_configuration = { 'mode' => 'local', 'public_key' => @valid_public_key}
40
+ @iut_configuration = {
41
+ 'mode' => 'remote',
42
+ 'generator-url' => 'http://authentication-token-generator-service:9393/generate',
43
+ 'validator-url' => 'http://authentication-token-validator-service:9393/validate'
44
+ }
31
45
  @iut = SoarAuthenticationToken::RackMiddleware.new(@test_app, @iut_configuration)
32
46
  end
33
47
 
data/spec/spec_helper.rb CHANGED
@@ -3,3 +3,4 @@ $LOAD_PATH.unshift File.expand_path('../../spec/support', __FILE__)
3
3
 
4
4
  require 'soar_authentication_token'
5
5
  require 'pry'
6
+ require 'auth_token_store_provider'
@@ -21,6 +21,8 @@ describe SoarAuthenticationToken::TokenGenerator do
21
21
  'generator-url' => 'http://authentication-token-generator-service:9393/generate',
22
22
  'validator-url' => 'http://authentication-token-validator-service:9393/validate'
23
23
  }
24
+
25
+ @test_store = AuthTokenStoreProvider::StubClient.new
24
26
  end
25
27
 
26
28
  after :each do
@@ -34,29 +36,33 @@ describe SoarAuthenticationToken::TokenGenerator do
34
36
  end
35
37
 
36
38
  context "when generating a new token locally" do
37
- it 'should provide token using configured private key' do
39
+ it 'should generate the token locally using configured private key' do
38
40
  @iut = SoarAuthenticationToken::TokenGenerator.new(@generator_configuration_local)
41
+ @iut.inject_store_provider(@test_store)
39
42
  @validator = SoarAuthenticationToken::TokenValidator.new(@validator_configuration_local)
43
+ @validator.inject_store_provider(@test_store)
40
44
 
41
45
  token = @iut.generate(authenticated_identifier: @test_authenticated_identifier, flow_identifier: 'test-flow-id')
42
- token_validity, token_identifier = @validator.validate(authentication_token: token, flow_identifier: 'test-flow-id')
46
+ token_validity, token_meta = @validator.validate(authentication_token: token, flow_identifier: 'test-flow-id')
43
47
 
44
48
  expect(token_validity).to eq(true)
45
- expect(token_identifier).to eq(@test_authenticated_identifier)
49
+ expect(token_meta['authenticated_identifier']).to eq(@test_authenticated_identifier)
46
50
  end
47
51
  end
48
52
 
49
53
  context "when generating a new token remotely" do
50
- it 'should provide token using the configured remote service' do
54
+ it 'should request the token from the configured remote service' do
51
55
  @iut = SoarAuthenticationToken::TokenGenerator.new(@configuration_remote)
56
+ @iut.inject_store_provider(@test_store)
52
57
 
53
58
  token = @iut.generate(authenticated_identifier: @test_authenticated_identifier, flow_identifier: 'test-flow-id')
54
59
 
55
60
  @validator = SoarAuthenticationToken::TokenValidator.new(@configuration_remote)
56
- token_validity, token_identifier = @validator.validate(authentication_token: token, flow_identifier: 'test-flow-id')
61
+ @iut.inject_store_provider(@test_store)
62
+ token_validity, token_meta = @validator.validate(authentication_token: token, flow_identifier: 'test-flow-id')
57
63
 
58
64
  expect(token_validity).to eq(true)
59
- expect(token_identifier).to eq(@test_authenticated_identifier)
65
+ expect(token_meta['authenticated_identifier']).to eq(@test_authenticated_identifier)
60
66
  end
61
67
  end
62
68
  end
@@ -3,6 +3,7 @@ require 'yaml'
3
3
 
4
4
  describe SoarAuthenticationToken::TokenValidator do
5
5
  before :all do
6
+ @test_store = AuthTokenStoreProvider::StubClient.new
6
7
  keypair_generator = SoarAuthenticationToken::KeypairGenerator.new
7
8
  @valid_private_key, @valid_public_key = keypair_generator.generate
8
9
  @invalid_private_key, @invalid_public_key = keypair_generator.generate
@@ -28,12 +29,15 @@ describe SoarAuthenticationToken::TokenValidator do
28
29
  'validator-url' => 'http://authentication-token-validator-service:9393/validate'
29
30
  }
30
31
  @local_valid_generator = SoarAuthenticationToken::TokenGenerator.new(@local_valid_generator_configuration)
32
+ @local_valid_generator.inject_store_provider(@test_store)
31
33
  @local_invalid_generator = SoarAuthenticationToken::TokenGenerator.new(@local_invalid_generator_configuration)
34
+ @local_invalid_generator.inject_store_provider(@test_store)
32
35
  @remote_generator = SoarAuthenticationToken::TokenGenerator.new(@remote_generator_configuration)
33
36
  end
34
37
 
35
38
  before :each do
36
39
  @iut_local = SoarAuthenticationToken::TokenValidator.new(@local_validator_configuration)
40
+ @iut_local.inject_store_provider(@test_store)
37
41
  @iut_remote = SoarAuthenticationToken::TokenValidator.new(@remote_validator_configuration)
38
42
  end
39
43
 
@@ -47,26 +51,26 @@ describe SoarAuthenticationToken::TokenValidator do
47
51
  context "when validating a token locally using the configured public key" do
48
52
  it 'should indicate valid if the token is valid' do
49
53
  token = @local_valid_generator.generate(authenticated_identifier: @test_identifier)
50
- token_validity, token_identifier = @iut_local.validate(authentication_token: token)
54
+ token_validity, token_meta = @iut_local.validate(authentication_token: token)
51
55
  expect(token_validity).to eq true
52
56
  end
53
57
 
54
58
  it 'should indicate invalid if the token is invalid' do
55
59
  token = @local_invalid_generator.generate(authenticated_identifier: @test_identifier)
56
- token_validity, token_identifier = @iut_local.validate(authentication_token: token)
60
+ token_validity, token_meta = @iut_local.validate(authentication_token: token)
57
61
  expect(token_validity).to eq false
58
62
  end
59
63
 
60
64
  it 'should provide the authenticated_identifier if the token is valid' do
61
65
  token = @local_valid_generator.generate(authenticated_identifier: @test_identifier)
62
- token_validity, token_identifier = @iut_local.validate(authentication_token: token)
63
- expect(token_identifier).to eq @test_identifier
66
+ token_validity, token_meta = @iut_local.validate(authentication_token: token)
67
+ expect(token_meta['authenticated_identifier']).to eq @test_identifier
64
68
  end
65
69
 
66
70
  it 'should not provide the authenticated_identifier if the token is invalid' do
67
71
  token = @local_invalid_generator.generate(authenticated_identifier: @test_identifier)
68
- token_validity, token_identifier = @iut_local.validate(authentication_token: token)
69
- expect(token_identifier).to eq nil
72
+ token_validity, token_meta = @iut_local.validate(authentication_token: token)
73
+ expect(token_meta).to eq nil
70
74
  end
71
75
 
72
76
  it 'should indicate as invalid tokens that are older than the configured expiry time' do
@@ -83,26 +87,26 @@ describe SoarAuthenticationToken::TokenValidator do
83
87
  context "when validating a token remotely using the configured url" do
84
88
  it 'should indicate valid if the token is valid' do
85
89
  token = @remote_generator.generate(authenticated_identifier: @test_identifier)
86
- token_validity, token_identifier = @iut_remote.validate(authentication_token: token)
90
+ token_validity, token_meta = @iut_remote.validate(authentication_token: token)
87
91
  expect(token_validity).to eq true
88
92
  end
89
93
 
90
94
  it 'should indicate invalid if the token is invalid' do
91
95
  token = @local_invalid_generator.generate(authenticated_identifier: @test_identifier)
92
- token_validity, token_identifier = @iut_remote.validate(authentication_token: token)
96
+ token_validity, token_meta = @iut_remote.validate(authentication_token: token)
93
97
  expect(token_validity).to eq false
94
98
  end
95
99
 
96
100
  it 'should provide the authenticated_identifier if the token is valid' do
97
101
  token = @remote_generator.generate(authenticated_identifier: @test_identifier)
98
- token_validity, token_identifier = @iut_remote.validate(authentication_token: token)
99
- expect(token_identifier).to eq @test_identifier
102
+ token_validity, token_meta = @iut_remote.validate(authentication_token: token)
103
+ expect(token_meta['authenticated_identifier']).to eq @test_identifier
100
104
  end
101
105
 
102
106
  it 'should not provide the authenticated_identifier if the token is invalid' do
103
107
  token = @local_invalid_generator.generate(authenticated_identifier: @test_identifier)
104
- token_validity, token_identifier = @iut_remote.validate(authentication_token: token)
105
- expect(token_identifier).to eq nil
108
+ token_validity, token_meta = @iut_remote.validate(authentication_token: token)
109
+ expect(token_meta).to eq nil
106
110
  end
107
111
 
108
112
  it 'should indicate as invalid tokens that are older than the configured expiry time' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: soar_authentication_token
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Barney de Villiers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-07 00:00:00.000000000 Z
11
+ date: 2017-01-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: soar_xt
@@ -64,6 +64,20 @@ dependencies:
64
64
  - - ">="
65
65
  - !ruby/object:Gem::Version
66
66
  version: 1.6.4
67
+ - !ruby/object:Gem::Dependency
68
+ name: auth_token_store_provider
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: 1.0.0
74
+ type: :runtime
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: 1.0.0
67
81
  - !ruby/object:Gem::Dependency
68
82
  name: pry
69
83
  requirement: !ruby/object:Gem::Requirement
@@ -151,6 +165,7 @@ extensions: []
151
165
  extra_rdoc_files: []
152
166
  files:
153
167
  - ".gitignore"
168
+ - ".gitmodules"
154
169
  - ".rspec"
155
170
  - ".ruby-gemset"
156
171
  - ".ruby-version"