soar_authentication_token 0.0.4 → 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/README.md +11 -1
- data/docker-compose.yml +1 -0
- data/lib/soar_authentication_token/rack_middleware.rb +11 -79
- data/lib/soar_authentication_token/version.rb +1 -1
- data/soar_authentication_token.gemspec +5 -3
- data/spec/rack_middleware_spec.rb +67 -0
- metadata +44 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cba64c87af18ce0cacb4333430c2056b2a8dbf4d
|
4
|
+
data.tar.gz: 2b78253b2ce7ed01e483075950e81400c8d7435b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 98fabb13ee0409d95199d7eceb98a1eed2af9c0f0b4a506e6e883ed9f762d488bdef6a5e786cac824f78a1437af3f32cd4b587e10a7ca1819e3a2d896a3512e5
|
7
|
+
data.tar.gz: ec3ec0e4f402d2effabe925dfbefe3e7b7413eb0462cd8e6b3765386828d40d690f95a21965241f6fd14c0e9f2d7b4bbb9bc8134d9eac7874358057cad1de56b
|
data/README.md
CHANGED
@@ -25,7 +25,17 @@ Or install it yourself as:
|
|
25
25
|
|
26
26
|
Run the rspec test tests using docker compose:
|
27
27
|
|
28
|
-
$ docker-compose
|
28
|
+
$ docker-compose build
|
29
|
+
$ docker-compose run --rm soar-authentication-token
|
30
|
+
|
31
|
+
Properly clean up containers afterwards:
|
32
|
+
|
33
|
+
$ docker-compose down
|
34
|
+
|
35
|
+
Locally run a subset:
|
36
|
+
|
37
|
+
$ bundle exec rspec -cfd spec/rack_middleware_spec.rb
|
38
|
+
|
29
39
|
|
30
40
|
## Usage
|
31
41
|
|
data/docker-compose.yml
CHANGED
@@ -1,97 +1,29 @@
|
|
1
|
-
require '
|
2
|
-
require 'cgi'
|
3
|
-
require 'net/http'
|
4
|
-
require 'nokogiri'
|
5
|
-
require 'rack/request'
|
6
|
-
require 'uri'
|
1
|
+
require 'rack'
|
7
2
|
|
8
3
|
module SoarAuthenticationToken
|
9
|
-
|
10
4
|
class RackMiddleware
|
11
|
-
|
12
|
-
def initialize(app, config)
|
5
|
+
def initialize(app, configuration)
|
13
6
|
@app = app
|
14
|
-
@
|
7
|
+
@configuration = configuration
|
15
8
|
end
|
16
9
|
|
17
10
|
def call(env)
|
18
11
|
request = Rack::Request.new env
|
19
|
-
|
12
|
+
session, params = request.session, request.params
|
13
|
+
valid, authenticated_identifier = validate_and_resolve_token(request.env['HTTP_AUTHORIZATION'],params['flow_identifier'])
|
14
|
+
if valid
|
15
|
+
session['user'] = authenticated_identifier
|
20
16
|
@app.call env
|
21
17
|
else
|
22
|
-
|
23
|
-
if session['user']
|
24
|
-
@app.call env
|
25
|
-
elsif params['logoutRequest']
|
26
|
-
callback(:on_logout, env, st_from_logoutrequest(params['logoutRequest']))
|
27
|
-
[200, {}, ['']]
|
28
|
-
elsif user = signon(request)
|
29
|
-
session['user'] = user
|
30
|
-
callback(:on_login, env, request['ticket'])
|
31
|
-
@app.call env
|
32
|
-
else
|
33
|
-
service = get_service request
|
34
|
-
[302, {'Location' => signon_url(service)}, ['']]
|
35
|
-
end
|
18
|
+
[401, {"Content-Type" => "text/html"}, ["401 - Not authenticated"]]
|
36
19
|
end
|
37
20
|
end
|
38
21
|
|
39
22
|
private
|
40
23
|
|
41
|
-
def
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
def st_from_logoutrequest(logout_request)
|
46
|
-
document = Nokogiri::XML::Document.parse(logout_request)
|
47
|
-
document.xpath('/samlp:LogoutRequest/samlp:SessionIndex').text
|
24
|
+
def validate_and_resolve_token(authentication_token,flow_identifier)
|
25
|
+
token_validator = SoarAuthenticationToken::TokenValidator.new(@configuration)
|
26
|
+
token_validator.validate(authentication_token: authentication_token,flow_identifier: flow_identifier)
|
48
27
|
end
|
49
|
-
|
50
|
-
|
51
|
-
def is_browser?(request)
|
52
|
-
ua = request.user_agent
|
53
|
-
Browser.new(ua: ua).id != :other
|
54
|
-
end
|
55
|
-
|
56
|
-
def signon(request)
|
57
|
-
ticket = request.params['ticket']
|
58
|
-
service = get_service(request)
|
59
|
-
if ticket and service
|
60
|
-
redeem_service_ticket(ticket, service)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def get_service(request)
|
65
|
-
url = request.url
|
66
|
-
url.gsub!(/\&ticket=ST-\w+/, '')
|
67
|
-
url.gsub!(/\?ticket=ST-\w+/, '?')
|
68
|
-
url.chomp('?')
|
69
|
-
end
|
70
|
-
|
71
|
-
def redeem_service_ticket(ticket, service)
|
72
|
-
uri = URI.parse validation_url(ticket, service)
|
73
|
-
req = Net::HTTP::Get.new(uri.to_s)
|
74
|
-
verify_mode = @config[:ignore_certificate] ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
|
75
|
-
Net::HTTP.start(uri.host, uri.port, :use_ssl => (uri.scheme == 'https'), :verify_mode => verify_mode) do |http|
|
76
|
-
response = http.request(req)
|
77
|
-
if response.code.to_i == 200
|
78
|
-
response_xml = Nokogiri::XML::Document.parse(response.body)
|
79
|
-
user_element = response_xml.xpath('/cas:serviceResponse/cas:authenticationSuccess/cas:user')
|
80
|
-
unless user_element.empty?
|
81
|
-
user_element.inner_text
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def signon_url(service = '')
|
88
|
-
"#{@config[:prefix]}/login?service=#{CGI.escape service}"
|
89
|
-
end
|
90
|
-
|
91
|
-
def validation_url(ticket, service)
|
92
|
-
"#{@config[:prefix]}/serviceValidate?ticket=#{ticket}&service=#{CGI.escape service}"
|
93
|
-
end
|
94
|
-
|
95
28
|
end
|
96
|
-
|
97
29
|
end
|
@@ -21,9 +21,11 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
spec.add_dependency 'soar_xt', '~> 0.0.3'
|
23
23
|
spec.add_dependency 'jwt', '~> 1.5', '>= 1.5.6'
|
24
|
+
spec.add_dependency "rack", '~> 1.6', '>= 1.6.4'
|
24
25
|
|
25
26
|
spec.add_development_dependency 'pry', '~> 0'
|
26
|
-
spec.add_development_dependency
|
27
|
-
spec.add_development_dependency
|
28
|
-
spec.add_development_dependency
|
27
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
28
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
29
|
+
spec.add_development_dependency 'rspec', '~> 2.13'
|
30
|
+
spec.add_development_dependency "capybara", '~> 2.1', '>= 2.1.0'
|
29
31
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rack'
|
3
|
+
require 'rack/test'
|
4
|
+
|
5
|
+
describe SoarAuthenticationToken::RackMiddleware do
|
6
|
+
include Rack::Test::Methods
|
7
|
+
|
8
|
+
def create_token_generator
|
9
|
+
keypair_generator = SoarAuthenticationToken::KeypairGenerator.new
|
10
|
+
private_key, public_key = keypair_generator.generate
|
11
|
+
configuration = {
|
12
|
+
'mode' => 'local',
|
13
|
+
'private_key' => private_key,
|
14
|
+
'public_key' => public_key
|
15
|
+
}
|
16
|
+
[ SoarAuthenticationToken::TokenGenerator.new(configuration), private_key, public_key ]
|
17
|
+
end
|
18
|
+
|
19
|
+
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
|
22
|
+
end
|
23
|
+
|
24
|
+
before :each do
|
25
|
+
@test_app = lambda do |env|
|
26
|
+
request = Rack::Request.new env
|
27
|
+
session = request.session
|
28
|
+
[200, {"Content-Type"=>"text/html"}, ["tested with authenticated user #{session['user']}"] ]
|
29
|
+
end
|
30
|
+
@iut_configuration = { 'mode' => 'local', 'public_key' => @valid_public_key}
|
31
|
+
@iut = SoarAuthenticationToken::RackMiddleware.new(@test_app, @iut_configuration)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'has a version number' do
|
35
|
+
expect(SoarAuthenticationToken::VERSION).not_to be nil
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when initialized" do
|
39
|
+
it 'remembers the app provided' do
|
40
|
+
expect(@iut.instance_variable_get("@app")).to eq(@test_app)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'remembers the configuration provided' do
|
44
|
+
expect(@iut.instance_variable_get("@configuration")).to eq(@iut_configuration)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when called with an environment" do
|
49
|
+
it "should return 401 if the request contains no authentication token" do
|
50
|
+
opts = { }
|
51
|
+
code, env, body = @iut.call Rack::MockRequest.env_for('http://service', opts)
|
52
|
+
expect([code, env, body]).to eq([401, {"Content-Type" => "text/html"}, ["401 - Not authenticated"]])
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should return 401 if the request contains an invalid authentication token" do
|
56
|
+
opts = { 'HTTP_AUTHORIZATION' => @local_invalid_generator.generate(authenticated_identifier: 'a@b.com') }
|
57
|
+
code, env, body = @iut.call Rack::MockRequest.env_for('http://service', opts)
|
58
|
+
expect([code, env, body]).to eq([401, {"Content-Type" => "text/html"}, ["401 - Not authenticated"]])
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should pass requests that are authenticated through to the application" do
|
62
|
+
opts = { 'HTTP_AUTHORIZATION' => @local_valid_generator.generate(authenticated_identifier: 'a@b.com') }
|
63
|
+
code, env, body = @iut.call Rack::MockRequest.env_for('http://service', opts)
|
64
|
+
expect([code, env, body]).to eq([200, {"Content-Type"=>"text/html"}, ["tested with authenticated user a@b.com"] ])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
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.0
|
4
|
+
version: 0.1.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-
|
11
|
+
date: 2016-12-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: soar_xt
|
@@ -44,6 +44,26 @@ dependencies:
|
|
44
44
|
- - ">="
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: 1.5.6
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rack
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.6'
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 1.6.4
|
57
|
+
type: :runtime
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '1.6'
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 1.6.4
|
47
67
|
- !ruby/object:Gem::Dependency
|
48
68
|
name: pry
|
49
69
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,6 +120,26 @@ dependencies:
|
|
100
120
|
- - "~>"
|
101
121
|
- !ruby/object:Gem::Version
|
102
122
|
version: '2.13'
|
123
|
+
- !ruby/object:Gem::Dependency
|
124
|
+
name: capybara
|
125
|
+
requirement: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - "~>"
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '2.1'
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: 2.1.0
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - "~>"
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '2.1'
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: 2.1.0
|
103
143
|
description: Interface to the authentication token service
|
104
144
|
email:
|
105
145
|
- barney.de.villiers@hetzner.co.za
|
@@ -137,6 +177,7 @@ files:
|
|
137
177
|
- sanity/sanity_benchmark.rb
|
138
178
|
- soar_authentication_token.gemspec
|
139
179
|
- spec/keypair_generator_spec.rb
|
180
|
+
- spec/rack_middleware_spec.rb
|
140
181
|
- spec/spec_helper.rb
|
141
182
|
- spec/token_generator_spec.rb
|
142
183
|
- spec/token_validator_spec.rb
|
@@ -166,6 +207,7 @@ specification_version: 4
|
|
166
207
|
summary: Client library for Hetzner's authentication token service
|
167
208
|
test_files:
|
168
209
|
- spec/keypair_generator_spec.rb
|
210
|
+
- spec/rack_middleware_spec.rb
|
169
211
|
- spec/spec_helper.rb
|
170
212
|
- spec/token_generator_spec.rb
|
171
213
|
- spec/token_validator_spec.rb
|