cf-uaac 4.30.0 → 5.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 +4 -4
- data/.github/workflows/release.yml +105 -0
- data/.github/workflows/ruby.yml +5 -2
- data/Gemfile +1 -1
- data/cf-uaac.gemspec +3 -4
- data/lib/uaa/stub/server.rb +73 -70
- data/lib/uaa/stub/uaa.rb +3 -3
- data/spec/http_spec.rb +52 -67
- data/spec/spec_helper.rb +4 -11
- data/spec/ssl_integration_spec.rb +0 -1
- data/version.txt +1 -1
- metadata +12 -39
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fd7760d3f031f0b442008a44934f109533b3c3603c3949c62bba59439a41eea7
|
|
4
|
+
data.tar.gz: b25c73922f6500e7b3e7a36c2a95390a6be055ea86a68b5ab3f73da2fdb45d34
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 58c337030166df2743c180ba2e2beeec9ff621e3c98875988a9d0c9a22f44db30a7926fcc9168697bf1faca0042ab64a066d205c8a304a07e0496d69c0b2df36
|
|
7
|
+
data.tar.gz: fd9603938d53dde1b7f48244bfdff6f5be857c40e2ffeba4e965a53b545a64e08dc81dc550b617181bf19d1728d376b9a9ae55f86993be5c940eeba3f11716e6
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
bump_type:
|
|
7
|
+
description: 'Type of version bump (major, minor, or patch)'
|
|
8
|
+
required: true
|
|
9
|
+
type: choice
|
|
10
|
+
default: 'patch'
|
|
11
|
+
options:
|
|
12
|
+
- major
|
|
13
|
+
- minor
|
|
14
|
+
- patch
|
|
15
|
+
|
|
16
|
+
run-name: "Ship ${{ inputs.bump_type }} Release"
|
|
17
|
+
|
|
18
|
+
concurrency:
|
|
19
|
+
group: serialize-releases-${{ github.repository }}
|
|
20
|
+
cancel-in-progress: false
|
|
21
|
+
|
|
22
|
+
permissions:
|
|
23
|
+
contents: write
|
|
24
|
+
|
|
25
|
+
jobs:
|
|
26
|
+
release:
|
|
27
|
+
name: Release gem and publish to RubyGems.org
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
if: github.ref == 'refs/heads/main'
|
|
30
|
+
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@v7
|
|
33
|
+
with:
|
|
34
|
+
fetch-depth: 0
|
|
35
|
+
|
|
36
|
+
- name: Set up Ruby
|
|
37
|
+
uses: ruby/setup-ruby@v1
|
|
38
|
+
with:
|
|
39
|
+
bundler-cache: true
|
|
40
|
+
ruby-version: '3.3'
|
|
41
|
+
|
|
42
|
+
- name: Setup Git
|
|
43
|
+
run: |
|
|
44
|
+
git config --global user.email "identity-uaa+ci@pivotal.io"
|
|
45
|
+
git config --global user.name "UAA Identity Bot"
|
|
46
|
+
|
|
47
|
+
- name: Set up Node.js (for npx semver)
|
|
48
|
+
uses: actions/setup-node@v4
|
|
49
|
+
with:
|
|
50
|
+
node-version: 'lts/*'
|
|
51
|
+
- name: Bump version from last tag
|
|
52
|
+
id: bump_version
|
|
53
|
+
run: |
|
|
54
|
+
prev_tag=$(git tag -l 'v*' --sort=-v:refname | head -n1)
|
|
55
|
+
prev_tag=${prev_tag:-v0.0.0}
|
|
56
|
+
version=${prev_tag#v}
|
|
57
|
+
new_version=$(npx -y semver -i ${{ inputs.bump_type }} "${version}")
|
|
58
|
+
|
|
59
|
+
echo "${new_version}" > version.txt
|
|
60
|
+
git add version.txt
|
|
61
|
+
git commit -m "Bump version to ${new_version}"
|
|
62
|
+
git push origin HEAD:${{ github.ref_name }}
|
|
63
|
+
|
|
64
|
+
echo "version=${new_version}" >> "$GITHUB_OUTPUT"
|
|
65
|
+
echo "prev_tag=${prev_tag}" >> "$GITHUB_OUTPUT"
|
|
66
|
+
echo "🤔 *Previous tag: ${prev_tag}*" >> $GITHUB_STEP_SUMMARY
|
|
67
|
+
echo "### 👷 Building ${new_version}" >> $GITHUB_STEP_SUMMARY
|
|
68
|
+
|
|
69
|
+
- name: Configure RubyGems credentials
|
|
70
|
+
run: |
|
|
71
|
+
mkdir -p ~/.gem
|
|
72
|
+
printf -- "---\n:rubygems_api_key: %s\n" "${RUBYGEMS_AUTH_TOKEN}" > ~/.gem/credentials
|
|
73
|
+
chmod 600 ~/.gem/credentials
|
|
74
|
+
env:
|
|
75
|
+
RUBYGEMS_AUTH_TOKEN: ${{ secrets.RUBYGEMS_AUTH_TOKEN }}
|
|
76
|
+
|
|
77
|
+
- name: Release gem
|
|
78
|
+
run: bundle exec rake release
|
|
79
|
+
|
|
80
|
+
- name: Create GitHub release
|
|
81
|
+
id: create_release
|
|
82
|
+
env:
|
|
83
|
+
GH_TOKEN: ${{ github.token }}
|
|
84
|
+
run: |
|
|
85
|
+
version=${{ steps.bump_version.outputs.version }}
|
|
86
|
+
prev_tag=${{ steps.bump_version.outputs.prev_tag }}
|
|
87
|
+
tag="v${version}"
|
|
88
|
+
|
|
89
|
+
if git rev-parse -q --verify "refs/tags/${prev_tag}"; then
|
|
90
|
+
change_range="${prev_tag}...${tag}"
|
|
91
|
+
else
|
|
92
|
+
change_range="${tag}"
|
|
93
|
+
fi
|
|
94
|
+
git log --pretty='* %s' "${change_range}" > changelog.md
|
|
95
|
+
|
|
96
|
+
html_url=$(gh release create "${tag}" \
|
|
97
|
+
"pkg/cf-uaac-${version}.gem" \
|
|
98
|
+
--title "${tag}" \
|
|
99
|
+
--notes-file changelog.md)
|
|
100
|
+
echo "html_url=${html_url}" >> "$GITHUB_OUTPUT"
|
|
101
|
+
|
|
102
|
+
- name: Summary
|
|
103
|
+
run: |
|
|
104
|
+
echo "### 🎉 Created release ${{ steps.bump_version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
|
|
105
|
+
echo "🌐 GitHub Release URL: ${{ steps.create_release.outputs.html_url }}" >> $GITHUB_STEP_SUMMARY
|
data/.github/workflows/ruby.yml
CHANGED
|
@@ -6,6 +6,9 @@ on:
|
|
|
6
6
|
pull_request:
|
|
7
7
|
branches: [ main ]
|
|
8
8
|
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
9
12
|
jobs:
|
|
10
13
|
test:
|
|
11
14
|
|
|
@@ -13,10 +16,10 @@ jobs:
|
|
|
13
16
|
strategy:
|
|
14
17
|
fail-fast: false
|
|
15
18
|
matrix:
|
|
16
|
-
ruby-version: ['
|
|
19
|
+
ruby-version: ['3.3', '3.4', '4.0']
|
|
17
20
|
|
|
18
21
|
steps:
|
|
19
|
-
- uses: actions/checkout@
|
|
22
|
+
- uses: actions/checkout@v7
|
|
20
23
|
- name: Set up Ruby
|
|
21
24
|
uses: ruby/setup-ruby@v1
|
|
22
25
|
with:
|
data/Gemfile
CHANGED
data/cf-uaac.gemspec
CHANGED
|
@@ -25,13 +25,14 @@ Gem::Specification.new do |s|
|
|
|
25
25
|
s.description = %q{Client command line tools for interacting with the CloudFoundry User Account and Authorization (UAA) server. The UAA is an OAuth2 Authorization Server so it can be used by webapps and command line apps to obtain access tokens to act on behalf of users. The tokens can then be used to access protected resources in a Resource Server. This library can be used by clients (as a convenient wrapper for mainstream oauth gems) or by resource servers.}
|
|
26
26
|
|
|
27
27
|
s.license = 'Apache-2.0'
|
|
28
|
+
s.required_ruby_version = '>= 3.3'
|
|
28
29
|
s.files = `git ls-files`.split("\n")
|
|
29
30
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
30
31
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
31
32
|
s.require_paths = ['lib']
|
|
32
33
|
|
|
33
34
|
# dependencies
|
|
34
|
-
s.add_runtime_dependency 'cf-uaa-lib', '~> 4.0.
|
|
35
|
+
s.add_runtime_dependency 'cf-uaa-lib', '~> 4.0.10'
|
|
35
36
|
s.add_development_dependency 'rake', '~> 13.0'
|
|
36
37
|
s.add_development_dependency 'rspec', '~> 3.12'
|
|
37
38
|
s.add_development_dependency 'simplecov', '~> 0.22.0'
|
|
@@ -39,9 +40,7 @@ Gem::Specification.new do |s|
|
|
|
39
40
|
s.add_development_dependency 'ci_reporter', '~> 2.1.0'
|
|
40
41
|
s.add_development_dependency 'ci_reporter_rspec', '~> 1.0'
|
|
41
42
|
s.add_runtime_dependency 'highline', '>= 2', '< 4'
|
|
42
|
-
s.add_runtime_dependency 'eventmachine', '~> 1.2'
|
|
43
43
|
s.add_runtime_dependency 'launchy', '>= 2.5', '< 4.0'
|
|
44
|
-
s.add_runtime_dependency '
|
|
45
|
-
s.add_runtime_dependency 'json', '~>2.7'
|
|
44
|
+
s.add_runtime_dependency 'json', '~> 2.19', '>= 2.19.3'
|
|
46
45
|
s.add_runtime_dependency 'rack', '~> 3.2', '>= 3.2.5'
|
|
47
46
|
end
|
data/lib/uaa/stub/server.rb
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
# subcomponent's license, as noted in the LICENSE file.
|
|
12
12
|
#++
|
|
13
13
|
|
|
14
|
-
require '
|
|
14
|
+
require 'socket'
|
|
15
15
|
require 'date'
|
|
16
16
|
require 'logger'
|
|
17
17
|
require 'pp'
|
|
@@ -33,7 +33,6 @@ class Request
|
|
|
33
33
|
private
|
|
34
34
|
|
|
35
35
|
def bslice(str, range)
|
|
36
|
-
# byteslice is available in ruby 1.9.3
|
|
37
36
|
str.respond_to?(:byteslice) ? str.byteslice(range) : str.slice(range)
|
|
38
37
|
end
|
|
39
38
|
|
|
@@ -64,7 +63,7 @@ class Request
|
|
|
64
63
|
|
|
65
64
|
public
|
|
66
65
|
|
|
67
|
-
# adds data to the request, returns
|
|
66
|
+
# adds data to the request, returns truthy if request is complete
|
|
68
67
|
def completed?(str)
|
|
69
68
|
str, @prelude = @prelude + str, "" unless @prelude.empty?
|
|
70
69
|
add_lines(str)
|
|
@@ -136,7 +135,6 @@ class Base
|
|
|
136
135
|
attr_accessor :request, :reply, :match, :server
|
|
137
136
|
|
|
138
137
|
def self.route(http_methods, matcher, filters = {}, &handler)
|
|
139
|
-
fail unless !EM.reactor_running? || EM.reactor_thread?
|
|
140
138
|
matcher = Regexp.new("^#{Regexp.escape(matcher.to_s)}$") unless matcher.is_a?(Regexp)
|
|
141
139
|
filters = filters.each_with_object({}) { |(k, v), o|
|
|
142
140
|
o[k.downcase] = v.is_a?(Regexp) ? v : Regexp.new("^#{Regexp.escape(v.to_s)}$")
|
|
@@ -156,7 +154,6 @@ class Base
|
|
|
156
154
|
end
|
|
157
155
|
|
|
158
156
|
def self.find_route(request)
|
|
159
|
-
fail unless EM.reactor_thread?
|
|
160
157
|
if @routes && (rary = @routes[request.method])
|
|
161
158
|
rary.each { |r; m|
|
|
162
159
|
next unless (m = r[0].match(request.path))
|
|
@@ -204,44 +201,60 @@ class Base
|
|
|
204
201
|
|
|
205
202
|
end
|
|
206
203
|
|
|
207
|
-
#------------------------------------------------------------------------------
|
|
208
|
-
module Connection
|
|
209
|
-
attr_accessor :req_handler
|
|
210
|
-
def unbind; req_handler.server.delete_connection(self) end
|
|
211
|
-
|
|
212
|
-
def receive_data(data)
|
|
213
|
-
#req_handler.server.logger.debug "got #{data.bytesize} bytes: #{data.inspect}"
|
|
214
|
-
return unless req_handler.request.completed? data
|
|
215
|
-
req_handler.process
|
|
216
|
-
send_data req_handler.reply.to_s
|
|
217
|
-
if req_handler.reply.headers['connection'] =~ /^close$/i || req_handler.server.status != :running
|
|
218
|
-
close_connection_after_writing
|
|
219
|
-
end
|
|
220
|
-
rescue Exception => e
|
|
221
|
-
req_handler.server.logger.debug "exception from receive_data: #{e.message}"
|
|
222
|
-
req_handler.server.trace { e.backtrace }
|
|
223
|
-
close_connection
|
|
224
|
-
end
|
|
225
|
-
end
|
|
226
|
-
|
|
227
204
|
#------------------------------------------------------------------------------
|
|
228
205
|
class Server
|
|
229
206
|
|
|
230
207
|
private
|
|
231
208
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
209
|
+
# Handle one TCP client socket: parse requests, dispatch, write replies.
|
|
210
|
+
# Supports keep-alive: the Request object resets itself after each
|
|
211
|
+
# completed? call, so the same req_handler is reused for pipelined requests.
|
|
212
|
+
def handle_client(socket)
|
|
213
|
+
req_handler = @req_handler.new(self)
|
|
214
|
+
loop do
|
|
215
|
+
# If leftover bytes from the previous request already complete the next
|
|
216
|
+
# one (pipelining / chunked reads), process without a blocking read.
|
|
217
|
+
unless req_handler.request.completed?("")
|
|
218
|
+
begin
|
|
219
|
+
data = socket.readpartial(4096)
|
|
220
|
+
rescue EOFError, Errno::ECONNRESET
|
|
221
|
+
break
|
|
222
|
+
end
|
|
223
|
+
next unless req_handler.request.completed?(data)
|
|
224
|
+
end
|
|
225
|
+
req_handler.process
|
|
226
|
+
socket.write(req_handler.reply.to_s)
|
|
227
|
+
break if req_handler.reply.headers['connection'] =~ /^close$/i || @status != :running
|
|
228
|
+
end
|
|
229
|
+
rescue Errno::ECONNRESET, Errno::EPIPE, IOError => e
|
|
230
|
+
logger.debug "connection error: #{e.message}"
|
|
231
|
+
ensure
|
|
232
|
+
socket.close rescue nil
|
|
233
|
+
@mutex.synchronize { @connections.delete(socket) }
|
|
234
|
+
logger.debug "connection closed"
|
|
238
235
|
end
|
|
239
236
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
237
|
+
# Accept connections in a loop until the server is stopped or the listening
|
|
238
|
+
# socket is closed.
|
|
239
|
+
def accept_loop
|
|
240
|
+
loop do
|
|
241
|
+
begin
|
|
242
|
+
socket = @tcp_server.accept_nonblock
|
|
243
|
+
@mutex.synchronize { @connections << socket }
|
|
244
|
+
logger.debug "starting connection"
|
|
245
|
+
Thread.new(socket) { |s| handle_client(s) }
|
|
246
|
+
rescue IO::WaitReadable, Errno::EINTR
|
|
247
|
+
IO.select([@tcp_server], nil, nil, 0.5) rescue nil
|
|
248
|
+
break if @status != :running
|
|
249
|
+
rescue Errno::EBADF, IOError
|
|
250
|
+
break
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
rescue => e
|
|
254
|
+
logger.debug "accept loop error: #{e.message}" unless e.is_a?(IOError) || e.is_a?(Errno::EBADF)
|
|
255
|
+
ensure
|
|
256
|
+
@status = :stopped
|
|
257
|
+
logger.debug "server really done"
|
|
245
258
|
end
|
|
246
259
|
|
|
247
260
|
public
|
|
@@ -258,64 +271,54 @@ class Server
|
|
|
258
271
|
@host = options[:host] || "localhost"
|
|
259
272
|
@init_port = options[:port] || 0
|
|
260
273
|
@root = options[:root]
|
|
261
|
-
@connections
|
|
274
|
+
@connections = []
|
|
275
|
+
@mutex = Mutex.new
|
|
276
|
+
@status = :stopped
|
|
277
|
+
@server_thread = nil
|
|
262
278
|
end
|
|
263
279
|
|
|
264
280
|
def start
|
|
265
281
|
raise ArgumentError, "attempt to start a server that's already running" unless @status == :stopped
|
|
266
282
|
logger.debug "starting #{self.class} server #{@host}"
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
logger.info "#{self.class} server started at #{url}"
|
|
271
|
-
end
|
|
283
|
+
@tcp_server = TCPServer.new(@host, @init_port)
|
|
284
|
+
@port = @tcp_server.addr[1]
|
|
285
|
+
logger.info "#{self.class} server started at #{url}"
|
|
272
286
|
@status = :running
|
|
273
287
|
self
|
|
274
288
|
end
|
|
275
289
|
|
|
290
|
+
# Start the server and run the accept loop on a background thread.
|
|
291
|
+
# Returns immediately; caller can use #url and #port right away.
|
|
276
292
|
def run_on_thread
|
|
277
|
-
raise ArgumentError, "can't run on thread,
|
|
278
|
-
logger.debug
|
|
279
|
-
|
|
280
|
-
@
|
|
281
|
-
begin
|
|
282
|
-
EM.run { start; cthred.run }
|
|
283
|
-
logger.debug "server thread done"
|
|
284
|
-
rescue Exception => e
|
|
285
|
-
logger.debug { "unhandled exception on stub server thread: #{e.message}" }
|
|
286
|
-
trace { e.backtrace }
|
|
287
|
-
raise
|
|
288
|
-
end
|
|
289
|
-
end
|
|
290
|
-
Thread.stop
|
|
293
|
+
raise ArgumentError, "can't run on thread, server already running" if @status == :running
|
|
294
|
+
logger.debug "starting server on thread"
|
|
295
|
+
start
|
|
296
|
+
@server_thread = Thread.new { accept_loop }
|
|
291
297
|
logger.debug "running on thread"
|
|
292
298
|
self
|
|
293
299
|
end
|
|
294
300
|
|
|
301
|
+
# Start the server and run the accept loop on the calling thread (blocking).
|
|
295
302
|
def run
|
|
296
|
-
raise ArgumentError, "can't run,
|
|
297
|
-
@
|
|
298
|
-
|
|
299
|
-
|
|
303
|
+
raise ArgumentError, "can't run, server already running" if @status == :running
|
|
304
|
+
@server_thread = Thread.current
|
|
305
|
+
start
|
|
306
|
+
accept_loop
|
|
307
|
+
logger.debug "server and event loop done"
|
|
300
308
|
end
|
|
301
309
|
|
|
302
|
-
#
|
|
303
|
-
#
|
|
304
|
-
# done until it's status is stopped.
|
|
305
|
-
# if not on reactor thread, wait until everything's cleaned up and stopped
|
|
310
|
+
# Stop accepting new connections, close the listening socket, and wait for
|
|
311
|
+
# the accept loop thread to mark status :stopped.
|
|
306
312
|
def stop
|
|
307
313
|
logger.debug "stopping server"
|
|
308
314
|
@status = :stopping
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
sleep 0.1 while @status != :stopped unless EM.reactor_thread?
|
|
315
|
+
@tcp_server.close rescue nil
|
|
316
|
+
sleep 0.05 while @status != :stopped
|
|
312
317
|
end
|
|
313
318
|
|
|
314
319
|
def delete_connection(conn)
|
|
315
320
|
logger.debug "deleting connection"
|
|
316
|
-
|
|
317
|
-
@connections.delete(conn)
|
|
318
|
-
done if @status != :running && @connections.empty?
|
|
321
|
+
@mutex.synchronize { @connections.delete(conn) }
|
|
319
322
|
end
|
|
320
323
|
|
|
321
324
|
end
|
data/lib/uaa/stub/uaa.rb
CHANGED
|
@@ -466,12 +466,12 @@ class StubUAAConn < Stub::Base
|
|
|
466
466
|
route :get, %r{^/Groups/External/list(\?|$)(.*)} do
|
|
467
467
|
return unless valid_token('scim.read')
|
|
468
468
|
|
|
469
|
-
query_params =
|
|
469
|
+
query_params = URI.decode_www_form(match[2]).to_h
|
|
470
470
|
|
|
471
|
-
start_index_param = query_params['startIndex']
|
|
471
|
+
start_index_param = query_params['startIndex'] || ''
|
|
472
472
|
start_index = start_index_param.empty? ? 1 : start_index_param.to_i
|
|
473
473
|
|
|
474
|
-
count_param = query_params['count']
|
|
474
|
+
count_param = query_params['count'] || ''
|
|
475
475
|
count = count_param.empty? ? 100 : count_param.to_i
|
|
476
476
|
|
|
477
477
|
group_mappings = server.scim.get_group_mappings
|
data/spec/http_spec.rb
CHANGED
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
require 'spec_helper'
|
|
15
15
|
require 'fiber'
|
|
16
16
|
require 'net/http'
|
|
17
|
-
require 'em-http'
|
|
18
17
|
require 'uaa/http'
|
|
19
18
|
require 'uaa/cli/version'
|
|
20
19
|
require 'uaa/stub/server'
|
|
@@ -42,56 +41,45 @@ describe Http do
|
|
|
42
41
|
|
|
43
42
|
after :all do @stub_http.stop if @stub_http end
|
|
44
43
|
|
|
45
|
-
it "gets something from stub server on a fiber" do
|
|
46
|
-
frequest(true) {
|
|
47
|
-
f = Fiber.current
|
|
48
|
-
http = EM::HttpRequest.new("#{@stub_http.url}/").get
|
|
49
|
-
http.errback { f.resume "error" }
|
|
50
|
-
http.callback {
|
|
51
|
-
http.response_header.http_status.should == 200
|
|
52
|
-
f.resume http.response
|
|
53
|
-
}
|
|
54
|
-
Fiber.yield
|
|
55
|
-
}.should match /welcome to stub http/
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
it "uses persistent connections from stubserver" do
|
|
59
|
-
frequest(true) {
|
|
60
|
-
f = Fiber.current
|
|
61
|
-
conn = EM::HttpRequest.new("#{@stub_http.url}/")
|
|
62
|
-
req1 = conn.get keepalive: true
|
|
63
|
-
req1.errback { f.resume "error1" }
|
|
64
|
-
req1.callback {
|
|
65
|
-
req2 = conn.get
|
|
66
|
-
req2.errback { f.resume req2.error }
|
|
67
|
-
req2.callback { f.resume req2.response }
|
|
68
|
-
}
|
|
69
|
-
Fiber.yield
|
|
70
|
-
}.should match /welcome to stub http/
|
|
71
|
-
end
|
|
72
|
-
|
|
73
44
|
it "gets something from stub server on a thread" do
|
|
74
45
|
@async = false
|
|
75
46
|
resp = Net::HTTP.get(URI("#{@stub_http.url}/"))
|
|
76
47
|
resp.should match /welcome to stub http/
|
|
77
48
|
end
|
|
78
49
|
|
|
50
|
+
it "reuses connections to the same host (connection caching)" do
|
|
51
|
+
# Replaces the old EM keepalive test. The Http module caches one HTTPClient
|
|
52
|
+
# instance per host via @http_cache; verify multiple sequential requests
|
|
53
|
+
# all succeed through that cache.
|
|
54
|
+
client = HttpClient.new
|
|
55
|
+
3.times do
|
|
56
|
+
status, body, _ = client.get(@stub_http.url, "/")
|
|
57
|
+
status.should == 200
|
|
58
|
+
body.should match /welcome to stub http/
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "works when called from a Ruby Fiber" do
|
|
63
|
+
# Replaces the old EM-fiber GET test. The HTTP client is synchronous, so
|
|
64
|
+
# calling it from a native Fiber must work without deadlocking.
|
|
65
|
+
result = nil
|
|
66
|
+
Fiber.new {
|
|
67
|
+
result = begin
|
|
68
|
+
status, body, _ = HttpClient.new.get(@stub_http.url, "/")
|
|
69
|
+
[status, body]
|
|
70
|
+
rescue => e
|
|
71
|
+
e
|
|
72
|
+
end
|
|
73
|
+
}.resume
|
|
74
|
+
result[0].should == 200
|
|
75
|
+
result[1].should match /welcome to stub http/
|
|
76
|
+
end
|
|
77
|
+
|
|
79
78
|
shared_examples_for "http client" do
|
|
80
79
|
|
|
81
|
-
# the following is intended to test that a failed dns lookup will fail
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
# configure the dhcp client with a dns server that will resolve
|
|
85
|
-
# every name as a valid address, e.g. bad.example.bad returns an address
|
|
86
|
-
# to a service signup screen. I have tried stubbing the code in various
|
|
87
|
-
# ways:
|
|
88
|
-
# EventMachine.stub(:connect) { raise EventMachine::ConnectionError, "fake error for bad dns lookup" }
|
|
89
|
-
# EventMachine.unstub(:connect)
|
|
90
|
-
# Socket.stub(:gethostbyname) { raise SocketError, "getaddrinfo: Name or service not known" }
|
|
91
|
-
# Socket.unstub(:gethostbyname)
|
|
92
|
-
# This has had varied success but seems rather brittle. Currently I have opted
|
|
93
|
-
# to just make the domain name invalid with tildes, but this may not test
|
|
94
|
-
# the desired code paths
|
|
80
|
+
# the following is intended to test that a failed dns lookup will fail
|
|
81
|
+
# cleanly. Some networks resolve every name, so tildes are used to ensure
|
|
82
|
+
# an invalid hostname.
|
|
95
83
|
it "fails cleanly for a failed dns lookup" do
|
|
96
84
|
result = frequest(@on_fiber) { @client.get("http://bad~host~name/") }
|
|
97
85
|
result.should be_an_instance_of BadTarget
|
|
@@ -125,39 +113,36 @@ describe Http do
|
|
|
125
113
|
end
|
|
126
114
|
end
|
|
127
115
|
|
|
128
|
-
context "on a
|
|
116
|
+
context "on a thread" do
|
|
129
117
|
before :all do
|
|
130
|
-
@on_fiber =
|
|
118
|
+
@on_fiber = false
|
|
131
119
|
@client = HttpClient.new
|
|
132
|
-
@client.set_request_handler do |url, method, body, headers|
|
|
133
|
-
f = Fiber.current
|
|
134
|
-
connection = EventMachine::HttpRequest.new(url, connect_timeout: 2, inactivity_timeout: 2)
|
|
135
|
-
client = connection.setup_request(method, head: headers, body: body)
|
|
136
|
-
|
|
137
|
-
# This check is for proper error handling with em-http-request 1.0.0.beta.3
|
|
138
|
-
if defined?(EventMachine::FailedConnection) && connection.is_a?(EventMachine::FailedConnection)
|
|
139
|
-
raise BadTarget, "HTTP connection setup error: #{client.error}"
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
client.callback { f.resume [client.response_header.http_status, client.response, client.response_header] }
|
|
143
|
-
client.errback { f.resume [:error, client.error] }
|
|
144
|
-
result = Fiber.yield
|
|
145
|
-
if result[0] == :error
|
|
146
|
-
raise BadTarget, "connection failed" unless result[1] && result[1] != ""
|
|
147
|
-
raise BadTarget, "connection refused" if result[1].to_s =~ /ECONNREFUSED/
|
|
148
|
-
raise BadTarget, "unable to resolve address" if /unable.*resolve.*address/.match result[1]
|
|
149
|
-
raise HTTPException, result[1]
|
|
150
|
-
end
|
|
151
|
-
[result[0], result[1], Util.hash_keys!(result[2], :dash)]
|
|
152
|
-
end
|
|
153
120
|
end
|
|
154
121
|
it_should_behave_like "http client"
|
|
155
122
|
end
|
|
156
123
|
|
|
157
|
-
|
|
124
|
+
# Replaces the old "on a fiber" context which ran the shared examples through
|
|
125
|
+
# an EventMachine async request handler via set_request_handler.
|
|
126
|
+
# Now exercises set_request_handler with a simple Net::HTTP backend,
|
|
127
|
+
# ensuring the callback interface itself works correctly.
|
|
128
|
+
context "with a custom request handler (Net::HTTP backend)" do
|
|
158
129
|
before :all do
|
|
159
130
|
@on_fiber = false
|
|
160
131
|
@client = HttpClient.new
|
|
132
|
+
@client.set_request_handler do |url, method, body, headers|
|
|
133
|
+
uri = URI.parse(url)
|
|
134
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
135
|
+
request = Net::HTTP::Get.new(uri.request_uri, headers)
|
|
136
|
+
begin
|
|
137
|
+
resp = http.request(request)
|
|
138
|
+
content_type = resp['content-type'] || ''
|
|
139
|
+
[resp.code.to_i, resp.body, {'content-type' => content_type}]
|
|
140
|
+
rescue SocketError, Errno::ECONNREFUSED, Errno::ECONNRESET => e
|
|
141
|
+
raise CF::UAA::BadTarget, e.message
|
|
142
|
+
rescue => e
|
|
143
|
+
raise CF::UAA::HTTPException, e.message
|
|
144
|
+
end
|
|
145
|
+
end
|
|
161
146
|
end
|
|
162
147
|
it_should_behave_like "http client"
|
|
163
148
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -23,7 +23,6 @@ if ENV['COVERAGE']
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
require 'rspec'
|
|
26
|
-
require 'eventmachine'
|
|
27
26
|
require 'uaa/stub/uaa'
|
|
28
27
|
|
|
29
28
|
RSpec.configure do |config|
|
|
@@ -42,16 +41,11 @@ module SpecHelper
|
|
|
42
41
|
e
|
|
43
42
|
end
|
|
44
43
|
|
|
45
|
-
# Runs given block
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
# restriction that the given block cannot include rspec matchers.
|
|
44
|
+
# Runs the given block and returns the result (or a captured exception).
|
|
45
|
+
# The on_fiber parameter is retained for API compatibility; with EventMachine
|
|
46
|
+
# removed it simply executes on the current thread.
|
|
49
47
|
def frequest(on_fiber, &blk)
|
|
50
|
-
|
|
51
|
-
result, cthred = nil, Thread.current
|
|
52
|
-
EM.schedule { Fiber.new { result = capture_exception(&blk); cthred.run }.resume }
|
|
53
|
-
Thread.stop
|
|
54
|
-
result
|
|
48
|
+
capture_exception(&blk)
|
|
55
49
|
end
|
|
56
50
|
|
|
57
51
|
def setup_target(opts = {})
|
|
@@ -100,4 +94,3 @@ module SpecHelper
|
|
|
100
94
|
end
|
|
101
95
|
|
|
102
96
|
end
|
|
103
|
-
|
data/version.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
5.0.0
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cf-uaac
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 5.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dave Syer
|
|
@@ -12,7 +12,7 @@ authors:
|
|
|
12
12
|
autorequire:
|
|
13
13
|
bindir: bin
|
|
14
14
|
cert_chain: []
|
|
15
|
-
date: 2026-
|
|
15
|
+
date: 2026-07-10 00:00:00.000000000 Z
|
|
16
16
|
dependencies:
|
|
17
17
|
- !ruby/object:Gem::Dependency
|
|
18
18
|
name: cf-uaa-lib
|
|
@@ -20,14 +20,14 @@ dependencies:
|
|
|
20
20
|
requirements:
|
|
21
21
|
- - "~>"
|
|
22
22
|
- !ruby/object:Gem::Version
|
|
23
|
-
version: 4.0.
|
|
23
|
+
version: 4.0.10
|
|
24
24
|
type: :runtime
|
|
25
25
|
prerelease: false
|
|
26
26
|
version_requirements: !ruby/object:Gem::Requirement
|
|
27
27
|
requirements:
|
|
28
28
|
- - "~>"
|
|
29
29
|
- !ruby/object:Gem::Version
|
|
30
|
-
version: 4.0.
|
|
30
|
+
version: 4.0.10
|
|
31
31
|
- !ruby/object:Gem::Dependency
|
|
32
32
|
name: rake
|
|
33
33
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -132,20 +132,6 @@ dependencies:
|
|
|
132
132
|
- - "<"
|
|
133
133
|
- !ruby/object:Gem::Version
|
|
134
134
|
version: '4'
|
|
135
|
-
- !ruby/object:Gem::Dependency
|
|
136
|
-
name: eventmachine
|
|
137
|
-
requirement: !ruby/object:Gem::Requirement
|
|
138
|
-
requirements:
|
|
139
|
-
- - "~>"
|
|
140
|
-
- !ruby/object:Gem::Version
|
|
141
|
-
version: '1.2'
|
|
142
|
-
type: :runtime
|
|
143
|
-
prerelease: false
|
|
144
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
145
|
-
requirements:
|
|
146
|
-
- - "~>"
|
|
147
|
-
- !ruby/object:Gem::Version
|
|
148
|
-
version: '1.2'
|
|
149
135
|
- !ruby/object:Gem::Dependency
|
|
150
136
|
name: launchy
|
|
151
137
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -167,39 +153,25 @@ dependencies:
|
|
|
167
153
|
- !ruby/object:Gem::Version
|
|
168
154
|
version: '4.0'
|
|
169
155
|
- !ruby/object:Gem::Dependency
|
|
170
|
-
name:
|
|
156
|
+
name: json
|
|
171
157
|
requirement: !ruby/object:Gem::Requirement
|
|
172
158
|
requirements:
|
|
173
159
|
- - "~>"
|
|
174
160
|
- !ruby/object:Gem::Version
|
|
175
|
-
version: '
|
|
161
|
+
version: '2.19'
|
|
176
162
|
- - ">="
|
|
177
163
|
- !ruby/object:Gem::Version
|
|
178
|
-
version:
|
|
164
|
+
version: 2.19.3
|
|
179
165
|
type: :runtime
|
|
180
166
|
prerelease: false
|
|
181
167
|
version_requirements: !ruby/object:Gem::Requirement
|
|
182
168
|
requirements:
|
|
183
169
|
- - "~>"
|
|
184
170
|
- !ruby/object:Gem::Version
|
|
185
|
-
version: '
|
|
171
|
+
version: '2.19'
|
|
186
172
|
- - ">="
|
|
187
173
|
- !ruby/object:Gem::Version
|
|
188
|
-
version:
|
|
189
|
-
- !ruby/object:Gem::Dependency
|
|
190
|
-
name: json
|
|
191
|
-
requirement: !ruby/object:Gem::Requirement
|
|
192
|
-
requirements:
|
|
193
|
-
- - "~>"
|
|
194
|
-
- !ruby/object:Gem::Version
|
|
195
|
-
version: '2.7'
|
|
196
|
-
type: :runtime
|
|
197
|
-
prerelease: false
|
|
198
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
199
|
-
requirements:
|
|
200
|
-
- - "~>"
|
|
201
|
-
- !ruby/object:Gem::Version
|
|
202
|
-
version: '2.7'
|
|
174
|
+
version: 2.19.3
|
|
203
175
|
- !ruby/object:Gem::Dependency
|
|
204
176
|
name: rack
|
|
205
177
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -241,6 +213,7 @@ extensions: []
|
|
|
241
213
|
extra_rdoc_files: []
|
|
242
214
|
files:
|
|
243
215
|
- ".github/dependabot.yml"
|
|
216
|
+
- ".github/workflows/release.yml"
|
|
244
217
|
- ".github/workflows/ruby.yml"
|
|
245
218
|
- ".gitignore"
|
|
246
219
|
- ".yardopts"
|
|
@@ -295,14 +268,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
295
268
|
requirements:
|
|
296
269
|
- - ">="
|
|
297
270
|
- !ruby/object:Gem::Version
|
|
298
|
-
version: '
|
|
271
|
+
version: '3.3'
|
|
299
272
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
300
273
|
requirements:
|
|
301
274
|
- - ">="
|
|
302
275
|
- !ruby/object:Gem::Version
|
|
303
276
|
version: '0'
|
|
304
277
|
requirements: []
|
|
305
|
-
rubygems_version: 3.
|
|
278
|
+
rubygems_version: 3.5.22
|
|
306
279
|
signing_key:
|
|
307
280
|
specification_version: 4
|
|
308
281
|
summary: Command line interface for CloudFoundry UAA
|