soar_authentication_token 0.1.0 → 1.0.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
  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"