cf-uaa-lib 3.6.0 → 3.14.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -4
- data/NOTICE +12 -0
- data/README.md +1 -1
- data/cf-uaa-lib.gemspec +16 -15
- data/lib/uaa/http.rb +62 -42
- data/lib/uaa/info.rb +6 -7
- data/lib/uaa/scim.rb +79 -25
- data/lib/uaa/token_coder.rb +19 -1
- data/lib/uaa/token_issuer.rb +1 -5
- data/lib/uaa/version.rb +1 -1
- data/spec/http_spec.rb +99 -54
- data/spec/info_spec.rb +36 -38
- data/spec/integration_spec.rb +197 -106
- data/spec/scim_spec.rb +89 -81
- data/spec/token_issuer_spec.rb +130 -135
- metadata +61 -12
- data/NOTICE.TXT +0 -10
- data/lib/uaa/proxy_options.rb +0 -30
- /data/{LICENSE.TXT → LICENSE} +0 -0
data/spec/http_spec.rb
CHANGED
@@ -15,83 +15,128 @@ require 'spec_helper'
|
|
15
15
|
require 'uaa/http'
|
16
16
|
require 'uaa/version'
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
describe Http do
|
18
|
+
describe CF::UAA::Http do
|
21
19
|
|
22
20
|
class HttpTest
|
23
|
-
include Http
|
21
|
+
include CF::UAA::Http
|
24
22
|
|
25
23
|
public :http_get
|
26
24
|
end
|
27
25
|
|
28
26
|
let(:http_instance) { HttpTest.new }
|
29
27
|
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
let(:http_double) do
|
29
|
+
http_double = double('http').as_null_object
|
30
|
+
expect(HTTPClient).to receive(:new).and_return(http_double)
|
31
|
+
http_double
|
32
|
+
end
|
33
|
+
|
34
|
+
let(:cert_store) { double('OpenSSL::X509::Store') }
|
35
|
+
|
36
|
+
describe 'set_request_handler' do
|
37
|
+
it 'sets a request handler' do
|
38
|
+
http_instance.set_request_handler do |url, method, body, headers|
|
39
|
+
[200, 'body', {'content-type' => 'text/plain'}]
|
40
|
+
end
|
41
|
+
status, body, resp_headers = http_instance.http_get('http://example.com')
|
42
|
+
status.should == 200
|
43
|
+
body.should == 'body'
|
44
|
+
resp_headers['content-type'].should == 'text/plain'
|
33
45
|
end
|
34
|
-
status, body, resp_headers = http_instance.http_get("http://example.com")
|
35
|
-
status.should == 200
|
36
|
-
body.should == "body"
|
37
|
-
resp_headers["content-type"].should == "text/plain"
|
38
46
|
end
|
39
47
|
|
40
|
-
|
41
|
-
reply_double = double('http reply', each_header: {}).as_null_object
|
42
|
-
http_double = double('http', request: reply_double, new: nil)
|
43
|
-
Net::HTTP.stub(:new).and_return(http_double)
|
44
|
-
http_instance.http_proxy = 'user:password@http-proxy.example.com:1234'
|
45
|
-
http_instance.https_proxy = 'user:password@https-proxy.example.com:1234'
|
48
|
+
describe 'http_get' do
|
46
49
|
|
47
|
-
|
50
|
+
context 'when response has no status' do
|
51
|
+
let(:response) { double('http::message') }
|
52
|
+
it 'raises an HTTPException error' do
|
53
|
+
expect(response).to receive(:status)
|
54
|
+
expect(response).to receive(:content).and_return('TEST')
|
55
|
+
expect(http_double).to receive(:get).and_return(response)
|
56
|
+
expect { http_instance.http_get('https://example.com') }.to raise_error(CF::UAA::HTTPException, "Can't parse response from the server TEST")
|
57
|
+
end
|
58
|
+
end
|
48
59
|
|
49
|
-
|
50
|
-
|
60
|
+
context 'when certificate is not valid' do
|
61
|
+
it 'raises an SSLException' do
|
62
|
+
expect(http_double).to receive(:get).and_raise(OpenSSL::SSL::SSLError)
|
51
63
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
http_double.stub(:request).and_raise(OpenSSL::SSL::SSLError)
|
64
|
+
expect { http_instance.http_get('https://example.com') }.to raise_error(CF::UAA::SSLException)
|
65
|
+
end
|
66
|
+
end
|
56
67
|
|
57
|
-
|
58
|
-
|
68
|
+
context 'when skipping ssl validation' do
|
69
|
+
let(:ssl_config) { double('ssl_config') }
|
59
70
|
|
60
|
-
|
61
|
-
|
62
|
-
Net::HTTP.stub(:new).and_return(http_double)
|
63
|
-
http_double.stub(:verify_mode=)
|
71
|
+
it 'sets verify mode to VERIFY_NONE' do
|
72
|
+
http_instance.initialize_http_options({skip_ssl_validation: true})
|
64
73
|
|
65
|
-
|
66
|
-
|
74
|
+
expect(http_double).to receive(:ssl_config).and_return(ssl_config)
|
75
|
+
expect(ssl_config).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
|
76
|
+
http_instance.http_get('https://uncached.example.com')
|
77
|
+
end
|
78
|
+
end
|
67
79
|
|
68
|
-
|
69
|
-
|
70
|
-
expect(http_double).to have_received(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
|
71
|
-
end
|
80
|
+
context 'when validating ssl' do
|
81
|
+
let(:ssl_config) { double('ssl_config') }
|
72
82
|
|
73
|
-
|
74
|
-
|
75
|
-
|
83
|
+
it 'sets default values' do
|
84
|
+
expect(http_double).to receive(:ssl_config).and_return(ssl_config)
|
85
|
+
expect(ssl_config).to receive(:set_default_paths)
|
86
|
+
http_instance.http_get('https://example.com')
|
87
|
+
end
|
88
|
+
end
|
76
89
|
|
77
|
-
|
78
|
-
|
90
|
+
context 'when ssl certificate is provided' do
|
91
|
+
let(:ssl_config) { double('ssl_config') }
|
79
92
|
|
80
|
-
|
81
|
-
|
82
|
-
end
|
93
|
+
it 'passes it' do
|
94
|
+
http_instance.initialize_http_options({ssl_ca_file: '/fake-ca-file'})
|
83
95
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
Net::HTTP.stub(:new).and_return(http_double)
|
96
|
+
expect(http_double).to receive(:ssl_config).and_return(ssl_config).twice
|
97
|
+
expect(ssl_config).to receive(:set_trust_ca).with('/fake-ca-file')
|
98
|
+
expect(ssl_config).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER)
|
88
99
|
|
89
|
-
|
90
|
-
|
100
|
+
http_instance.http_get('https://uncached.example.com')
|
101
|
+
end
|
102
|
+
end
|
91
103
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
104
|
+
context 'when ssl cert store is provided' do
|
105
|
+
let(:ssl_config) { double('ssl_config') }
|
106
|
+
|
107
|
+
it 'passes it' do
|
108
|
+
http_instance.initialize_http_options({ssl_cert_store: cert_store})
|
109
|
+
|
110
|
+
expect(http_double).to receive(:ssl_config).and_return(ssl_config).twice
|
111
|
+
expect(ssl_config).to receive(:cert_store=).with(cert_store)
|
112
|
+
expect(ssl_config).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER)
|
113
|
+
|
114
|
+
http_instance.http_get('https://uncached.example.com')
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'when an http request timeout is provided' do
|
119
|
+
it 'sets all timeouts on the http clien to the http_timeout' do
|
120
|
+
http_instance.initialize_http_options({http_timeout: 10})
|
96
121
|
|
122
|
+
expect(http_double).to receive(:connect_timeout=).with(10)
|
123
|
+
expect(http_double).to receive(:send_timeout=).with(10)
|
124
|
+
expect(http_double).to receive(:receive_timeout=).with(10)
|
125
|
+
|
126
|
+
http_instance.http_get('https://uncached.example.com')
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'when an http request timeout is not provided' do
|
131
|
+
it 'does not override the default' do
|
132
|
+
http_instance.initialize_http_options({})
|
133
|
+
|
134
|
+
expect(http_double).not_to receive(:connect_timeout=)
|
135
|
+
expect(http_double).not_to receive(:send_timeout=)
|
136
|
+
expect(http_double).not_to receive(:receive_timeout=)
|
137
|
+
|
138
|
+
http_instance.http_get('https://uncached.example.com')
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
97
142
|
end
|
data/spec/info_spec.rb
CHANGED
@@ -19,44 +19,42 @@ module CF::UAA
|
|
19
19
|
describe Info do
|
20
20
|
let(:options) { {} }
|
21
21
|
let(:uaa_info) { Info.new(target, options) }
|
22
|
-
let(:target) {
|
22
|
+
let(:target) { 'https://login.cloudfoundry.com' }
|
23
23
|
let(:authorization) { nil }
|
24
24
|
|
25
25
|
before do
|
26
26
|
uaa_info.set_request_handler do |url, method, body, headers|
|
27
27
|
url.should == target_url
|
28
28
|
method.should == :get
|
29
|
-
headers[
|
30
|
-
headers[
|
31
|
-
headers[
|
32
|
-
[200, response_body, {
|
29
|
+
headers['content-type'].should be_nil
|
30
|
+
headers['accept'].gsub(/\s/, '').should =~ /application\/json;charset=utf-8/i
|
31
|
+
headers['authorization'].should == authorization
|
32
|
+
[200, response_body, {'content-type' => 'application/json'}]
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
describe
|
37
|
-
let(:options) { {:
|
36
|
+
describe 'initialize' do
|
37
|
+
let(:options) { {:skip_ssl_validation => true} }
|
38
38
|
|
39
|
-
it
|
40
|
-
uaa_info.http_proxy.should == 'http-proxy.com'
|
41
|
-
uaa_info.https_proxy.should == 'https-proxy.com'
|
39
|
+
it 'sets proxy information' do
|
42
40
|
uaa_info.skip_ssl_validation == true
|
43
41
|
end
|
44
42
|
end
|
45
43
|
|
46
|
-
describe
|
47
|
-
let(:target_url) {
|
44
|
+
describe 'getting server info' do
|
45
|
+
let(:target_url) { 'https://login.cloudfoundry.com/login' }
|
48
46
|
let(:response_body) { '{"commit_id":"12345","prompts":["one","two"]}' }
|
49
47
|
|
50
|
-
it
|
48
|
+
it 'gets server info' do
|
51
49
|
result = uaa_info.server
|
52
|
-
result[
|
53
|
-
result[
|
50
|
+
result['prompts'].should_not be_nil
|
51
|
+
result['commit_id'].should_not be_nil
|
54
52
|
end
|
55
53
|
|
56
|
-
context
|
54
|
+
context 'with symbolize_keys keys true' do
|
57
55
|
let(:options) { {:symbolize_keys => true} }
|
58
56
|
|
59
|
-
it
|
57
|
+
it 'gets server info' do
|
60
58
|
result = uaa_info.server
|
61
59
|
result[:prompts].should_not be_nil
|
62
60
|
result[:commit_id].should_not be_nil
|
@@ -64,63 +62,63 @@ module CF::UAA
|
|
64
62
|
end
|
65
63
|
end
|
66
64
|
|
67
|
-
describe
|
68
|
-
let(:target) {
|
69
|
-
let(:target_url) {
|
65
|
+
describe 'getting UAA target' do
|
66
|
+
let(:target) { 'https://login.cloudfoundry.com' }
|
67
|
+
let(:target_url) { 'https://login.cloudfoundry.com/login' }
|
70
68
|
let(:response_body) { '{"links":{"uaa":"https://uaa.cloudfoundry.com"},"prompts":["one","two"]}' }
|
71
69
|
|
72
|
-
it
|
70
|
+
it 'gets UAA target' do
|
73
71
|
result = uaa_info.discover_uaa
|
74
|
-
result.should ==
|
72
|
+
result.should == 'https://uaa.cloudfoundry.com'
|
75
73
|
end
|
76
74
|
|
77
75
|
context "when there is no 'links' key present" do
|
78
|
-
let(:target) {
|
79
|
-
let(:target_url) {
|
76
|
+
let(:target) { 'https://uaa.cloudfoundry.com' }
|
77
|
+
let(:target_url) { 'https://uaa.cloudfoundry.com/login' }
|
80
78
|
let(:response_body) { '{ "prompts" : ["one","two"]} ' }
|
81
79
|
|
82
|
-
it
|
80
|
+
it 'returns the target url' do
|
83
81
|
result = uaa_info.discover_uaa
|
84
|
-
result.should ==
|
82
|
+
result.should == 'https://uaa.cloudfoundry.com'
|
85
83
|
end
|
86
84
|
end
|
87
85
|
|
88
|
-
context
|
86
|
+
context 'with symbolize_keys keys true' do
|
89
87
|
let(:options) { {:symbolize_keys => true} }
|
90
88
|
|
91
|
-
it
|
89
|
+
it 'gets UAA target' do
|
92
90
|
result = uaa_info.discover_uaa
|
93
|
-
result.should ==
|
91
|
+
result.should == 'https://uaa.cloudfoundry.com'
|
94
92
|
end
|
95
93
|
end
|
96
94
|
end
|
97
95
|
|
98
|
-
describe
|
99
|
-
let(:target_url) {
|
96
|
+
describe 'whoami' do
|
97
|
+
let(:target_url) { 'https://login.cloudfoundry.com/userinfo?schema=openid' }
|
100
98
|
let(:response_body) { '{"user_id":"1111-1111-1111-1111","user_name":"user","given_name":"first","family_name":"last","name":"first last","email":"email@example.com"}' }
|
101
99
|
let(:authorization) { 'authentication_token' }
|
102
100
|
|
103
|
-
it
|
101
|
+
it 'returns the user info' do
|
104
102
|
result = uaa_info.whoami(authorization)
|
105
103
|
result['email'].should == 'email@example.com'
|
106
104
|
end
|
107
105
|
end
|
108
106
|
|
109
|
-
describe
|
110
|
-
let(:target_url) {
|
107
|
+
describe 'validation_key' do
|
108
|
+
let(:target_url) { 'https://login.cloudfoundry.com/token_key' }
|
111
109
|
let(:response_body) { '{"alg":"SHA256withRSA","value":"-----BEGIN PUBLIC KEY-----\nabc123\n-----END PUBLIC KEY-----\n"}' }
|
112
110
|
|
113
|
-
it
|
111
|
+
it 'returns the key data' do
|
114
112
|
result = uaa_info.validation_key(authorization)
|
115
113
|
result['alg'].should == 'SHA256withRSA'
|
116
114
|
end
|
117
115
|
end
|
118
116
|
|
119
|
-
describe
|
120
|
-
let(:target_url) {
|
117
|
+
describe 'validation keys' do
|
118
|
+
let(:target_url) { 'https://login.cloudfoundry.com/token_keys' }
|
121
119
|
let(:response_body) { '{ "keys": [ { "kid": "the_key", "alg": "SHA256withRSA", "value": "-----BEGIN PUBLIC KEY-----\nabc123\n-----END PUBLIC KEY-----\n", "kty": "RSA", "use": "sig", "n": "Ufn7Qc", "e": "EEXZ" }, { "kid": "the_other_key", "alg": "SHA256withRSA", "value": "-----BEGIN PUBLIC KEY-----\ndef456\n-----END PUBLIC KEY-----\n", "kty": "RSA", "use": "sig", "n": "AMcW9/P", "e": "AQAB" } ] }' }
|
122
120
|
|
123
|
-
it
|
121
|
+
it 'returns a hash of keys' do
|
124
122
|
result = uaa_info.validation_keys_hash(authorization)
|
125
123
|
|
126
124
|
the_key = result['the_key']
|