castanet-testing 0.0.1
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 +7 -0
- data/.gitignore +19 -0
- data/.travis.yml +7 -0
- data/CHANGELOG +4 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/Procfile +2 -0
- data/README +50 -0
- data/Rakefile +5 -0
- data/assets/callback/callback.rb +190 -0
- data/assets/jasig/jetty.xml.erb +36 -0
- data/assets/jasig/jetty.xml.patch +28 -0
- data/assets/test.crt +19 -0
- data/assets/test.key +15 -0
- data/castanet-testing.gemspec +26 -0
- data/lib/castanet/testing.rb +9 -0
- data/lib/castanet/testing/asset_paths.rb +17 -0
- data/lib/castanet/testing/callback_server_tasks.rb +76 -0
- data/lib/castanet/testing/common_tasks.rb +29 -0
- data/lib/castanet/testing/connection_testing.rb +28 -0
- data/lib/castanet/testing/jasig_server_tasks.rb +190 -0
- data/lib/castanet/testing/namespacing.rb +15 -0
- data/lib/castanet/testing/version.rb +5 -0
- data/test.sh +29 -0
- metadata +152 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ba7386f0f2b4c9dcbd87159b1439b088de18c42b
|
4
|
+
data.tar.gz: 886b574886eb12ffeaa301fb9c9f88d2427437a9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1d325e9a92d0c3448c600a66b35ffc78c3aeb551451d355365808a68517a30c211dc2477111dc67860e3f6660c748e7fc7d21e837701cccc437ead067363547f
|
7
|
+
data.tar.gz: ecf4967bf03daff3194fa6033a67208aa9cf01f7f3d01f0aeaa80a84228e129d8ef589934d23343a6533b8ed84fceac43b371a19f425917e8e042df819a83528
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CHANGELOG
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 David Yip
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Procfile
ADDED
data/README
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
1. castanet-testing
|
2
|
+
|
3
|
+
Castanet[1] contains Rake tasks to start the Jasig CAS Server[2] and a CAS
|
4
|
+
proxy callback in a test environment.
|
5
|
+
|
6
|
+
This gem contains an adaptation of those tasks for use in other projects.
|
7
|
+
|
8
|
+
2. Requirements
|
9
|
+
|
10
|
+
* A Ruby environment: Ruby 1.9.3, JRuby 1.7.0, and Rubinius 2.0.0 are
|
11
|
+
regularly tested
|
12
|
+
* curl(1)
|
13
|
+
* openssl(1)
|
14
|
+
* patch(1)
|
15
|
+
* test(1)
|
16
|
+
* GNU tar
|
17
|
+
|
18
|
+
3. Usage
|
19
|
+
|
20
|
+
In a Rakefile:
|
21
|
+
|
22
|
+
require 'castanet/testing'
|
23
|
+
|
24
|
+
Castanet::Testing::JasigServerTasks.new
|
25
|
+
Castanet::Testing::CallbackServerTasks.new
|
26
|
+
|
27
|
+
This will install the following tasks:
|
28
|
+
|
29
|
+
castanet:testing:jasig:start
|
30
|
+
castanet:testing:jasig:waitall
|
31
|
+
castanet:testing:jasig:cleanall
|
32
|
+
castanet:testing:callback:start
|
33
|
+
castanet:testing:callback:waitall
|
34
|
+
castanet:testing:callback:cleanall
|
35
|
+
|
36
|
+
The start tasks can be used on their own or as part of a Procfile. If used in
|
37
|
+
a Procfile, you may freely vary concurrency levels. (Often, however, you'll
|
38
|
+
want just one server instance.)
|
39
|
+
|
40
|
+
All *Tasks classes have optional parameters. See the class docs for more
|
41
|
+
information.
|
42
|
+
|
43
|
+
4. License and authorship
|
44
|
+
|
45
|
+
Copyright (c) 2013 David Yip. Made available under the MIT license.
|
46
|
+
|
47
|
+
[1]: https://github.com/NUBIC/castanet
|
48
|
+
[2]: http://www.jasig.org/cas
|
49
|
+
|
50
|
+
# vim:ts=2:sw=2:et:tw=78
|
data/Rakefile
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'webrick/https'
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
##
|
6
|
+
# Rack code for handling the PGT callback part of the CAS proxy
|
7
|
+
# authentication protocol. The class itself is middleware; it can
|
8
|
+
# also generate an {.application endpoint}.
|
9
|
+
#
|
10
|
+
# ## Behavior
|
11
|
+
#
|
12
|
+
# As middleware, this class intercepts and handles two paths and
|
13
|
+
# passes all other requests down the chain. The paths are:
|
14
|
+
#
|
15
|
+
# * `/receive_pgt`: implements the PGT callback process per section
|
16
|
+
# 2.5.4 of the CAS protocol.
|
17
|
+
# * `/retrieve_pgt`: allows an application to retrieve the PGT for
|
18
|
+
# a PGTIOU. The PGTIOU is returned to the application as part of
|
19
|
+
# the CAS ticket validation process. It should be passed to
|
20
|
+
# `/receive_pgt` as the `pgtIou` query parameter. Note that a
|
21
|
+
# given PGT may only be retrieved once.
|
22
|
+
#
|
23
|
+
# As a full rack app, it handles the same two paths and returns `404
|
24
|
+
# Not Found` for all other requests.
|
25
|
+
#
|
26
|
+
# ## Middleware vs. Application
|
27
|
+
#
|
28
|
+
# It is **only** appropriate to use the class as middleware in a
|
29
|
+
# **multithreaded or multiprocessing deployment**. If your application
|
30
|
+
# only has one executor at a time, using this class as middleware
|
31
|
+
# **will cause a deadlock** during CAS authentication.
|
32
|
+
#
|
33
|
+
# ## Based on
|
34
|
+
#
|
35
|
+
# This class was heavily influenced by `CasProxyCallbackController`
|
36
|
+
# in rubycas-client. That class has approximately the same
|
37
|
+
# behavior, but is Rails-specific.
|
38
|
+
#
|
39
|
+
# @see http://www.jasig.org/cas/protocol
|
40
|
+
# CAS protocol, section 2.5.4
|
41
|
+
class RackProxyCallback
|
42
|
+
RETRIEVE_PATH = "/retrieve_pgt"
|
43
|
+
RECEIVE_PATH = "/receive_pgt"
|
44
|
+
|
45
|
+
##
|
46
|
+
# Create a new instance of the middleware.
|
47
|
+
#
|
48
|
+
# @param [#call] app the next rack application in the chain.
|
49
|
+
# @param [Hash] options
|
50
|
+
# @option options [String] :store the file where the middleware
|
51
|
+
# will store the received PGTs until they are retrieved.
|
52
|
+
def initialize(app, options={})
|
53
|
+
@app = app
|
54
|
+
@pgts = {}
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Handles a single request in the manner specified in the class
|
59
|
+
# overview.
|
60
|
+
#
|
61
|
+
# @param [Hash] env the rack environment for the request.
|
62
|
+
#
|
63
|
+
# @return [Array] an appropriate rack response.
|
64
|
+
def call(env)
|
65
|
+
return echo if env["PATH_INFO"] == "/"
|
66
|
+
return receive(env) if env["PATH_INFO"] == RECEIVE_PATH
|
67
|
+
return retrieve(env) if env["PATH_INFO"] == RETRIEVE_PATH
|
68
|
+
@app.call(env)
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Creates a rack application which responds as described in the
|
73
|
+
# class overview.
|
74
|
+
#
|
75
|
+
# @param [Hash] options the same options that you can pass to
|
76
|
+
# {#initialize}.
|
77
|
+
#
|
78
|
+
# @return [#call] a full rack application
|
79
|
+
def self.application(options={})
|
80
|
+
app = lambda { |env|
|
81
|
+
[404, { "Content-Type" => "text/plain" }, ["Unknown resource #{env['PATH_INFO']}"]]
|
82
|
+
}
|
83
|
+
new(app, options)
|
84
|
+
end
|
85
|
+
|
86
|
+
protected
|
87
|
+
|
88
|
+
##
|
89
|
+
# Associates the given PGTIOU and PGT.
|
90
|
+
#
|
91
|
+
# @param [String] pgt_iou
|
92
|
+
# @param [String] pgt
|
93
|
+
#
|
94
|
+
# @return [void]
|
95
|
+
def store_iou(pgt_iou, pgt)
|
96
|
+
@pgts[pgt_iou] = pgt
|
97
|
+
end
|
98
|
+
|
99
|
+
##
|
100
|
+
# Finds the PGT for the given PGTIOU. If there isn't one, it
|
101
|
+
# returns nil. If there is one, it deletes it from the store
|
102
|
+
# before returning it.
|
103
|
+
#
|
104
|
+
# @param [String] pgt_iou
|
105
|
+
# @return [String,nil]
|
106
|
+
def resolve_iou(pgt_iou)
|
107
|
+
@pgts.delete(pgt_iou)
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def echo
|
113
|
+
Rack::Response.new.tap do |r|
|
114
|
+
r.status = 200
|
115
|
+
end.finish
|
116
|
+
end
|
117
|
+
|
118
|
+
def receive(env)
|
119
|
+
req = Rack::Request.new(env)
|
120
|
+
resp = Rack::Response.new
|
121
|
+
resp.headers["Content-Type"] = "text/plain"
|
122
|
+
|
123
|
+
pgt = req.params["pgtId"]
|
124
|
+
pgt_iou = req.params["pgtIou"]
|
125
|
+
|
126
|
+
unless pgt && pgt_iou
|
127
|
+
missing = [("pgtId" unless pgt), ("pgtIou" unless pgt_iou)].compact
|
128
|
+
missing_msg =
|
129
|
+
if missing.size == 1
|
130
|
+
"#{missing.first} is a required query parameter."
|
131
|
+
else
|
132
|
+
"Both #{missing.join(' and ')} are required query parameters."
|
133
|
+
end
|
134
|
+
resp.status =
|
135
|
+
if missing.size == 2
|
136
|
+
#
|
137
|
+
# This oddity is required by the JA-SIG CAS Server.
|
138
|
+
#
|
139
|
+
200
|
140
|
+
else
|
141
|
+
400
|
142
|
+
end
|
143
|
+
|
144
|
+
resp.body = ["#{missing_msg}\nSee section 2.5.4 of the CAS protocol specification."]
|
145
|
+
else
|
146
|
+
store_iou(pgt_iou, pgt)
|
147
|
+
|
148
|
+
resp.body = ["PGT and PGTIOU received. Thanks, my robotic friend."]
|
149
|
+
end
|
150
|
+
|
151
|
+
resp.finish
|
152
|
+
end
|
153
|
+
|
154
|
+
def retrieve(env)
|
155
|
+
req = Rack::Request.new(env)
|
156
|
+
resp = Rack::Response.new
|
157
|
+
resp.headers["Content-Type"] = "text/plain"
|
158
|
+
|
159
|
+
pgt_iou = req.params["pgtIou"]
|
160
|
+
|
161
|
+
if pgt_iou
|
162
|
+
pgt = resolve_iou(pgt_iou)
|
163
|
+
if pgt
|
164
|
+
resp.body = [pgt]
|
165
|
+
else
|
166
|
+
resp.status = 404
|
167
|
+
resp.body = ["pgtIou=#{pgt_iou} does not exist. Perhaps it has already been retrieved."]
|
168
|
+
end
|
169
|
+
else
|
170
|
+
resp.status = 400
|
171
|
+
resp.body = ["pgtIou is a required query parameter."]
|
172
|
+
end
|
173
|
+
|
174
|
+
resp.finish
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# ----------------------------------------------------------------------------
|
179
|
+
|
180
|
+
trap('INT') { exit! }
|
181
|
+
trap('TERM') { exit! }
|
182
|
+
|
183
|
+
# Start it up.
|
184
|
+
Rack::Handler::WEBrick.run(RackProxyCallback.application, {
|
185
|
+
:BindAddress => ENV['HOST'],
|
186
|
+
:Port => ENV['PORT'] || 9292,
|
187
|
+
:SSLEnable => true,
|
188
|
+
:SSLCertificate => OpenSSL::X509::Certificate.new(File.read(ENV['SSL_CERT_PATH'])),
|
189
|
+
:SSLPrivateKey => OpenSSL::PKey::RSA.new(File.read(ENV['SSL_KEY_PATH']))
|
190
|
+
})
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
3
|
+
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
4
|
+
<New id="sslContextFactory" class="org.eclipse.jetty.http.ssl.SslContextFactory">
|
5
|
+
<Set name="KeyStore"><%= jetty_keystore %></Set>
|
6
|
+
<Set name="KeyStorePassword"><%= jetty_storepass %></Set>
|
7
|
+
<Set name="TrustStore"><%= jetty_keystore %></Set>
|
8
|
+
<Set name="TrustStorePassword"><%= jetty_storepass %></Set>
|
9
|
+
<Set name="IncludeCipherSuites">
|
10
|
+
<Array type="java.lang.String">
|
11
|
+
<Item>TLS_DHE_RSA_WITH_AES_128_CBC_SHA</Item>
|
12
|
+
</Array>
|
13
|
+
</Set>
|
14
|
+
</New>
|
15
|
+
<Call class="java.lang.System" name="setProperty">
|
16
|
+
<Arg>javax.net.ssl.trustStore</Arg>
|
17
|
+
<Arg><%= jetty_keystore %></Arg>
|
18
|
+
</Call>
|
19
|
+
<Call class="java.lang.System" name="setProperty">
|
20
|
+
<Arg>javax.net.ssl.trustStorePassword</Arg>
|
21
|
+
<Arg><%= jetty_storepass %></Arg>
|
22
|
+
</Call>
|
23
|
+
<Call name="addConnector">
|
24
|
+
<Arg>
|
25
|
+
<New class="org.eclipse.jetty.server.ssl.SslSelectChannelConnector">
|
26
|
+
<Arg><Ref id="sslContextFactory" /></Arg>
|
27
|
+
<Set name="Port">
|
28
|
+
<Property name="jetty.ssl_port" default="<%= port %>" />
|
29
|
+
</Set>
|
30
|
+
<Set name="maxIdleTime">30000</Set>
|
31
|
+
<Set name="Acceptors">2</Set>
|
32
|
+
<Set name="AcceptQueueSize">100</Set>
|
33
|
+
</New>
|
34
|
+
</Arg>
|
35
|
+
</Call>
|
36
|
+
</Configure>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
--- a/jetty.xml 2012-10-24 18:06:23.000000000 -0500
|
2
|
+
+++ b/jetty.xml 2012-10-24 18:06:29.000000000 -0500
|
3
|
+
@@ -30,25 +30,6 @@
|
4
|
+
</Set>
|
5
|
+
|
6
|
+
<!-- =========================================================== -->
|
7
|
+
- <!-- Set connectors -->
|
8
|
+
- <!-- =========================================================== -->
|
9
|
+
-
|
10
|
+
- <Call name="addConnector">
|
11
|
+
- <Arg>
|
12
|
+
- <New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
|
13
|
+
- <Set name="host"><Property name="jetty.host" /></Set>
|
14
|
+
- <Set name="port"><Property name="jetty.port" default="8080"/></Set>
|
15
|
+
- <Set name="maxIdleTime">300000</Set>
|
16
|
+
- <Set name="Acceptors">2</Set>
|
17
|
+
- <Set name="statsOn">false</Set>
|
18
|
+
- <Set name="confidentialPort">8443</Set>
|
19
|
+
- <Set name="lowResourcesConnections">20000</Set>
|
20
|
+
- <Set name="lowResourcesMaxIdleTime">5000</Set>
|
21
|
+
- </New>
|
22
|
+
- </Arg>
|
23
|
+
- </Call>
|
24
|
+
-
|
25
|
+
- <!-- =========================================================== -->
|
26
|
+
<!-- Set handler Collection Structure -->
|
27
|
+
<!-- =========================================================== -->
|
28
|
+
<Set name="handler">
|
data/assets/test.crt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDGDCCAoGgAwIBAgIJAKFL1LzPfLCMMA0GCSqGSIb3DQEBBQUAMGYxCzAJBgNV
|
3
|
+
BAYTAlVTMREwDwYDVQQIEwhBbnlzdGF0ZTEQMA4GA1UEBxMHQW55Y2l0eTEeMBwG
|
4
|
+
A1UEChMVQ2FzdGFuZXQgQ2xpY2tlcnMgTExDMRIwEAYDVQQDEwlsb2NhbGhvc3Qw
|
5
|
+
IBcNMTEwMTI0MDYyNjQ0WhgPMjA2NzAyMTkwNjI2NDRaMGYxCzAJBgNVBAYTAlVT
|
6
|
+
MREwDwYDVQQIEwhBbnlzdGF0ZTEQMA4GA1UEBxMHQW55Y2l0eTEeMBwGA1UEChMV
|
7
|
+
Q2FzdGFuZXQgQ2xpY2tlcnMgTExDMRIwEAYDVQQDEwlsb2NhbGhvc3QwgZ8wDQYJ
|
8
|
+
KoZIhvcNAQEBBQADgY0AMIGJAoGBALGnCOPNqDcUuLpJ6+IDOq9Vfr16pOOdVZfC
|
9
|
+
8YeeaQtii/UfeJztFzlYgnH0/Tvrld8n6EwQ8UhzXi0agJ3fGqBfEyUGs4eNOU/A
|
10
|
+
lIa3kltiPUhzxvZKAs8LqRuMamD3TY70ezPPdnkQSg2HGM2N++I8AHEBSCg6vKA0
|
11
|
+
N7UCquJ/AgMBAAGjgcswgcgwHQYDVR0OBBYEFLXPKVU6xeWwyxYPwA8/oxuNcaMV
|
12
|
+
MIGYBgNVHSMEgZAwgY2AFLXPKVU6xeWwyxYPwA8/oxuNcaMVoWqkaDBmMQswCQYD
|
13
|
+
VQQGEwJVUzERMA8GA1UECBMIQW55c3RhdGUxEDAOBgNVBAcTB0FueWNpdHkxHjAc
|
14
|
+
BgNVBAoTFUNhc3RhbmV0IENsaWNrZXJzIExMQzESMBAGA1UEAxMJbG9jYWxob3N0
|
15
|
+
ggkAoUvUvM98sIwwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCIT5TQ
|
16
|
+
ZGiMkUBlDSfMcRl9vDazZnoNjKIKHl4+3ta4YsmhkAGXiFmkuKrNXd7f8UDNf6Sw
|
17
|
+
irJNGIg6x146DLe6ZXqoaBSiof0lR10A/H3dl5RvfS1y2ma2tMJJwR7prHvRHgBn
|
18
|
+
kfg5FSOWxkzANC/hYU8/9Q7ceXNkmKklzinG9w==
|
19
|
+
-----END CERTIFICATE-----
|
data/assets/test.key
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
MIICXAIBAAKBgQCxpwjjzag3FLi6SeviAzqvVX69eqTjnVWXwvGHnmkLYov1H3ic
|
3
|
+
7Rc5WIJx9P0765XfJ+hMEPFIc14tGoCd3xqgXxMlBrOHjTlPwJSGt5JbYj1Ic8b2
|
4
|
+
SgLPC6kbjGpg902O9Hszz3Z5EEoNhxjNjfviPABxAUgoOrygNDe1AqrifwIDAQAB
|
5
|
+
AoGAXYcp9/zC7dS7+F+IjyHSGJLzOcBC5Q5lDJP2Ysb0WKkWNAPQlRWBX5CIhIRN
|
6
|
+
eelqquSwuLNGxDTwxOAqDHNz6U/oNBpImap+IXJgPv+uGokCXclmbONQ57sJCC5u
|
7
|
+
7Afznw9xMYMEI7pKwId+bfM9ehbJvaQC+PpxGTYrHhqf7AkCQQDaTC72cU7i8FFw
|
8
|
+
dNjT4MnasnptZiaitVFaJDLh/cp0wJ8B0YygFb9F2A/3qwDkCixKPa5SxFshh6Od
|
9
|
+
cHx9+56NAkEA0FXEWw7uAg25ye8waLCjsSFKodU+2KMwApw4Qp163YSY94kYk/Qm
|
10
|
+
CGVPxojv7o7Rup6G9JTYGywwhkZD7Ji4OwJBALt07GcoiguLPwQI8yGPSQeKeGN1
|
11
|
+
cvwKJB/6Mc+rNq3nsyPGpLHbuvLpRVzy9cLdkYb3TLk6cN9sMO5D6EPvTQkCQBwA
|
12
|
+
u0DmE9XQ1H0xGleoDoibifWQvT7PSH/BUcqack5eKVV0ZwpUEdylCYENHPr61XP5
|
13
|
+
JPixHQ8h9G/H+A9QQ8sCQCfMZZo6ozDUzMw59DQf4WfKuCSY4G3NGPblL2T+7Pt8
|
14
|
+
0jzvfyJLtgShYx2SBYXa+oCwN9o3d0Y6W1Yzlm8n0dg=
|
15
|
+
-----END RSA PRIVATE KEY-----
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'castanet/testing/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "castanet-testing"
|
8
|
+
spec.version = Castanet::Testing::VERSION
|
9
|
+
spec.authors = ["David Yip"]
|
10
|
+
spec.email = ["yipdw@northwestern.edu"]
|
11
|
+
spec.summary = %q{Contains Rake tasks for managing CAS servers in test environments}
|
12
|
+
spec.homepage = ""
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
21
|
+
spec.add_development_dependency "foreman", "0.63.0"
|
22
|
+
spec.add_development_dependency "yard"
|
23
|
+
spec.add_dependency "json"
|
24
|
+
spec.add_dependency "rack"
|
25
|
+
spec.add_dependency "rake", "~> 10.0"
|
26
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'castanet/testing'
|
2
|
+
|
3
|
+
module Castanet::Testing
|
4
|
+
module AssetPaths
|
5
|
+
def asset_path(p)
|
6
|
+
File.expand_path("../../../../assets/#{p}", __FILE__)
|
7
|
+
end
|
8
|
+
|
9
|
+
def ssl_key_path
|
10
|
+
asset_path('test.key')
|
11
|
+
end
|
12
|
+
|
13
|
+
def ssl_cert_path
|
14
|
+
asset_path('test.crt')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'castanet/testing'
|
2
|
+
require 'castanet/testing/asset_paths'
|
3
|
+
require 'castanet/testing/common_tasks'
|
4
|
+
require 'castanet/testing/namespacing'
|
5
|
+
require 'rake'
|
6
|
+
|
7
|
+
module Castanet::Testing
|
8
|
+
class CallbackServerTasks
|
9
|
+
extend AssetPaths
|
10
|
+
include CommonTasks
|
11
|
+
include Namespacing
|
12
|
+
include Rake::DSL
|
13
|
+
|
14
|
+
DEFAULT_SCRATCH_DIR = '/tmp/castanet-testing/callback'
|
15
|
+
DEFAULT_HOST = 'localhost'
|
16
|
+
DEFAULT_SSL_KEY = ssl_key_path
|
17
|
+
DEFAULT_SSL_CERT = ssl_cert_path
|
18
|
+
DEFAULT_TIMEOUT = 120
|
19
|
+
|
20
|
+
CALLBACK_PATH = asset_path('callback/callback.rb')
|
21
|
+
RUNNER = asset_path('run.rb')
|
22
|
+
|
23
|
+
# @option opts [String] :root ('castanet:testing:callback') namespaces for
|
24
|
+
# this task; an empty string means toplevel namespace
|
25
|
+
# @option opts [String] :scratch_dir ('/tmp/castanet-testing/callback')
|
26
|
+
# sets a path for downloads, server scratch space, etc.
|
27
|
+
# @option opts [String] :host ('localhost') hostname to bind
|
28
|
+
# @option opts [String] :ssl_cert (DEFAULT_SSL_CERT) the SSL certificate
|
29
|
+
# file to use
|
30
|
+
# @option opts [String] :ssl_key (DEFAULT_SSL_KEY) the SSL key file to use
|
31
|
+
# @option opts [String] :timeout (DEFAULT_TIMEOUT) timeout for waitall
|
32
|
+
def initialize(options = {})
|
33
|
+
root = options[:root] || 'castanet:testing:callback'
|
34
|
+
scratch_dir = options[:scratch_dir] || DEFAULT_SCRATCH_DIR
|
35
|
+
host = options[:host] || DEFAULT_HOST
|
36
|
+
ssl_cert = options[:ssl_cert] || DEFAULT_SSL_CERT
|
37
|
+
ssl_key = options[:ssl_key] || DEFAULT_SSL_KEY
|
38
|
+
timeout = options[:timeout] || DEFAULT_TIMEOUT
|
39
|
+
|
40
|
+
port = ENV['PORT']
|
41
|
+
instance_dir = "#{scratch_dir}/callback.#{$$}"
|
42
|
+
|
43
|
+
namespaces(root.split(':')) do
|
44
|
+
file instance_dir do
|
45
|
+
mkdir_p instance_dir
|
46
|
+
end
|
47
|
+
|
48
|
+
task :ensure_port do
|
49
|
+
raise "PORT is not set" unless port
|
50
|
+
end
|
51
|
+
|
52
|
+
task :prep => [:ensure_port, instance_dir]
|
53
|
+
|
54
|
+
desc 'Start a CAS proxy callback instance (requires PORT to be set)'
|
55
|
+
task :start => :prep do
|
56
|
+
ENV['HOST'] = host
|
57
|
+
ENV['SSL_CERT_PATH'] = ssl_cert
|
58
|
+
ENV['SSL_KEY_PATH'] = ssl_key
|
59
|
+
|
60
|
+
cd(instance_dir) { load(CALLBACK_PATH) }
|
61
|
+
end
|
62
|
+
|
63
|
+
desc "Wait for all CAS proxy callback instances in #{scratch_dir} to become ready"
|
64
|
+
task(:waitall) { wait_all(scratch_dir, timeout) }
|
65
|
+
|
66
|
+
desc "Clean up all CAS proxy callback instances under #{scratch_dir}"
|
67
|
+
task(:cleanall) { clean_all(scratch_dir, 'callback') }
|
68
|
+
|
69
|
+
desc "Delete #{scratch_dir}"
|
70
|
+
task :delete_scratch_dir do
|
71
|
+
rm_rf scratch_dir
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'castanet/testing'
|
2
|
+
require 'castanet/testing/connection_testing'
|
3
|
+
require 'json'
|
4
|
+
require 'rake'
|
5
|
+
require 'timeout'
|
6
|
+
|
7
|
+
module Castanet::Testing
|
8
|
+
module CommonTasks
|
9
|
+
include Castanet::Testing::ConnectionTesting
|
10
|
+
include Rake::DSL
|
11
|
+
|
12
|
+
def wait_all(scratch_dir, timeout)
|
13
|
+
Timeout.timeout(timeout) do
|
14
|
+
loop do
|
15
|
+
urls = Dir["#{scratch_dir}/**/.urls"].map { |x| JSON.parse(File.read(x))['status'] }
|
16
|
+
urls.reject! { |u| responding?(u) }
|
17
|
+
break true if urls.empty?
|
18
|
+
sleep 1
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def clean_all(scratch_dir, prefix)
|
24
|
+
files = FileList["#{scratch_dir}/#{prefix}.*"]
|
25
|
+
|
26
|
+
rm_rf files unless files.empty?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'castanet/testing'
|
2
|
+
require 'logger'
|
3
|
+
require 'net/http'
|
4
|
+
require 'openssl'
|
5
|
+
require 'uri'
|
6
|
+
|
7
|
+
module Castanet::Testing
|
8
|
+
module ConnectionTesting
|
9
|
+
LOGGER = Logger.new($stderr)
|
10
|
+
|
11
|
+
def responding?(url, logger = LOGGER)
|
12
|
+
uri = URI(url)
|
13
|
+
|
14
|
+
begin
|
15
|
+
h = Net::HTTP.new(uri.host, uri.port)
|
16
|
+
h.use_ssl = (uri.scheme == 'https')
|
17
|
+
h.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
18
|
+
resp = h.get(uri.request_uri)
|
19
|
+
code = resp.code.to_i
|
20
|
+
|
21
|
+
(200..399).include?(code)
|
22
|
+
rescue => e
|
23
|
+
logger.debug "#{url}: #{e.class} (#{e.message})"
|
24
|
+
false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'castanet/testing'
|
2
|
+
require 'castanet/testing/asset_paths'
|
3
|
+
require 'castanet/testing/common_tasks'
|
4
|
+
require 'castanet/testing/namespacing'
|
5
|
+
require 'erb'
|
6
|
+
require 'json'
|
7
|
+
require 'rake'
|
8
|
+
require 'shellwords'
|
9
|
+
require 'openssl'
|
10
|
+
require 'uri'
|
11
|
+
|
12
|
+
module Castanet::Testing
|
13
|
+
class JasigServerTasks
|
14
|
+
extend AssetPaths
|
15
|
+
include CommonTasks
|
16
|
+
include Rake::DSL
|
17
|
+
include Namespacing
|
18
|
+
include Shellwords
|
19
|
+
|
20
|
+
DEFAULT_SCRATCH_DIR = '/tmp/castanet-testing/jasig'
|
21
|
+
DEFAULT_JASIG_URL = 'http://downloads.jasig.org/cas/cas-server-3.5.2-release.tar.gz'
|
22
|
+
DEFAULT_JETTY_URL = 'http://archive.eclipse.org/jetty/8.1.7.v20120910/dist/jetty-distribution-8.1.7.v20120910.tar.gz'
|
23
|
+
DEFAULT_JASIG_CHECKSUM = 'e93e05acad4975c5caa1c20dff7c57ff8e846253bbf68ea8a5fc0199ce608cba'
|
24
|
+
DEFAULT_JETTY_CHECKSUM = 'a65d20367839bf3df7d32a05992678487ba8daeebb41d9833975aee46ffe86c2'
|
25
|
+
DEFAULT_MOUNT_POINT = '/cas'
|
26
|
+
DEFAULT_HOST = 'localhost'
|
27
|
+
DEFAULT_SSL_KEY = ssl_key_path
|
28
|
+
DEFAULT_SSL_CERT = ssl_cert_path
|
29
|
+
DEFAULT_TIMEOUT = 120
|
30
|
+
|
31
|
+
JETTY_SSL_CONFIG_TEMPLATE = asset_path('jasig/jetty.xml.erb')
|
32
|
+
JETTY_CONFIG_PATCHFILE = asset_path('jasig/jetty.xml.patch')
|
33
|
+
RUNNER = asset_path('jasig/run.sh')
|
34
|
+
|
35
|
+
##
|
36
|
+
# This is a ridiculous amount of setup for a CAS server.
|
37
|
+
#
|
38
|
+
# @option opts [String] :root ('castanet:testing:jasig') namespaces for
|
39
|
+
# this task; an empty string means toplevel namespace
|
40
|
+
# @option opts [String] :scratch_dir ('/tmp/castanet-testing/jasig') sets
|
41
|
+
# a path for downloads, server scratch space, etc.
|
42
|
+
# @option opts [String] :jasig_url (DEFAULT_JASIG_URL) the Jasig CAS Server
|
43
|
+
# package to download
|
44
|
+
# @option opts [String] :jasig_checksum (DEFAULT_JASIG_CHECKSUM) SHA256
|
45
|
+
# checksum of the CAS package
|
46
|
+
# @option opts [String] :jetty_url (DEFAULT_JETTY_URL) the Jetty
|
47
|
+
# distribution to download
|
48
|
+
# @option opts [String] :jetty_checksum (DEFAULT_JETTY_CHECKSUM) SHA256
|
49
|
+
# checksum of the Jetty package
|
50
|
+
# @option opts [String] :mount_point ('/cas') where the CAS server will be
|
51
|
+
# mounted
|
52
|
+
# @option opts [String] :host ('localhost') hostname to bind
|
53
|
+
# @option opts [String] :ssl_cert (DEFAULT_SSL_CERT) the SSL certificate
|
54
|
+
# file to use
|
55
|
+
# @option opts [String] :ssl_key (DEFAULT_SSL_KEY) the SSL key file to use
|
56
|
+
# @option opts [String] :timeout (DEFAULT_TIMEOUT) timeout for waitall
|
57
|
+
def initialize(options = {})
|
58
|
+
root = options[:root] || 'castanet:testing:jasig'
|
59
|
+
scratch_dir = options[:scratch_dir] || DEFAULT_SCRATCH_DIR
|
60
|
+
jasig_url = options[:jasig_url] || DEFAULT_JASIG_URL
|
61
|
+
jasig_checksum = options[:jasig_checksum] || DEFAULT_JASIG_CHECKSUM
|
62
|
+
jetty_url = options[:jetty_url] || DEFAULT_JETTY_URL
|
63
|
+
jetty_checksum = options[:jetty_checksum] || DEFAULT_JETTY_CHECKSUM
|
64
|
+
mount_point = options[:mount_point] || DEFAULT_MOUNT_POINT
|
65
|
+
host = options[:host] || DEFAULT_HOST
|
66
|
+
ssl_cert = options[:ssl_cert] || DEFAULT_SSL_CERT
|
67
|
+
ssl_key = options[:ssl_key] || DEFAULT_SSL_KEY
|
68
|
+
timeout = options[:timeout] || DEFAULT_TIMEOUT
|
69
|
+
|
70
|
+
instance_dir = "#{scratch_dir}/jasig.#{$$}"
|
71
|
+
port = ENV['PORT']
|
72
|
+
|
73
|
+
jasig_fn = URI.parse(jasig_url).path.split('/').last
|
74
|
+
jasig_package_dest = "#{scratch_dir}/#{jasig_fn}"
|
75
|
+
jasig_extract_dest = "#{scratch_dir}/#{jasig_fn}-extract"
|
76
|
+
jasig_war_filename = mount_point.split('/').last + '.war'
|
77
|
+
|
78
|
+
# Older versions of the Jasig CAS server used the cas-server-webapp*.war
|
79
|
+
# pattern. There's usually only one WAR in a Jasig CAS server
|
80
|
+
# distribution, though, so we just look for all of them and pick the first one.
|
81
|
+
jasig_package_name = FileList["#{jasig_extract_dest}/modules/*.war"]
|
82
|
+
|
83
|
+
jetty_fn = URI.parse(jetty_url).path.split('/').last
|
84
|
+
jetty_package_dest = "#{scratch_dir}/#{jetty_fn}"
|
85
|
+
jetty_war_filename = mount_point.split('/').last + '.war'
|
86
|
+
|
87
|
+
jetty_keystore = "#{instance_dir}/jetty.ks"
|
88
|
+
jetty_storepass = "secret"
|
89
|
+
jetty_ssl_config = "#{jetty_package_dest}/etc/jetty-cas-ssl.xml"
|
90
|
+
|
91
|
+
namespaces(root.split(':')) do
|
92
|
+
file jasig_package_dest do
|
93
|
+
mkdir_p scratch_dir
|
94
|
+
sh "curl -s #{e jasig_url} > #{e jasig_package_dest}"
|
95
|
+
verify_checksum(jasig_package_dest, jasig_checksum)
|
96
|
+
end
|
97
|
+
|
98
|
+
file jetty_package_dest do
|
99
|
+
mkdir_p scratch_dir
|
100
|
+
sh "curl -s #{e jetty_url} > #{e jetty_package_dest}"
|
101
|
+
verify_checksum(jetty_package_dest, jetty_checksum)
|
102
|
+
end
|
103
|
+
|
104
|
+
file jasig_extract_dest do
|
105
|
+
mkdir_p jasig_extract_dest
|
106
|
+
sh "tar xf #{e jasig_package_dest} -C #{e jasig_extract_dest} --strip-components 1"
|
107
|
+
end
|
108
|
+
|
109
|
+
file instance_dir do
|
110
|
+
mkdir_p instance_dir
|
111
|
+
sh "tar xf #{e jetty_package_dest} -C #{e instance_dir} --strip-components 1"
|
112
|
+
end
|
113
|
+
|
114
|
+
task :ensure_port do
|
115
|
+
raise "PORT is not set" unless port
|
116
|
+
end
|
117
|
+
|
118
|
+
desc 'Download the CAS server'
|
119
|
+
task :download => [jasig_package_dest, jasig_extract_dest, jetty_package_dest]
|
120
|
+
|
121
|
+
task :prep => [:download, :ensure_port, instance_dir] do
|
122
|
+
mkdir_p instance_dir
|
123
|
+
cp jasig_package_name.compact.first, "#{instance_dir}/webapps/#{jasig_war_filename}"
|
124
|
+
|
125
|
+
sh %Q{openssl pkcs12 -inkey #{e ssl_key} -in #{e ssl_cert} -export \
|
126
|
+
-out #{e "#{instance_dir}/jetty.pkcs12"} \
|
127
|
+
-password #{e "pass:#{jetty_storepass}"}}
|
128
|
+
|
129
|
+
sh %Q{keytool -destkeystore #{e jetty_keystore} -importkeystore \
|
130
|
+
-srckeystore #{e "#{instance_dir}/jetty.pkcs12"} \
|
131
|
+
-srcstoretype PKCS12 -srcstorepass #{e jetty_storepass} \
|
132
|
+
-storepass #{e jetty_storepass} -noprompt}
|
133
|
+
|
134
|
+
ssl_config = ERB.new(File.read(JETTY_SSL_CONFIG_TEMPLATE)).result(binding)
|
135
|
+
ssl_file = "#{instance_dir}/etc/jetty-cas-ssl.xml"
|
136
|
+
|
137
|
+
File.open(ssl_file, 'w') { |f| f.write(ssl_config) }
|
138
|
+
|
139
|
+
ini = File.read("#{instance_dir}/start.ini")
|
140
|
+
|
141
|
+
unless ini.include?(ssl_file)
|
142
|
+
File.open("#{instance_dir}/start.ini", 'a+') do |f|
|
143
|
+
f.write(ssl_file)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Delete the default connector.
|
148
|
+
patchfile = File.expand_path('../jetty.xml.patch', __FILE__)
|
149
|
+
|
150
|
+
cd "#{instance_dir}/etc" do
|
151
|
+
sh "patch -p1 < #{e JETTY_CONFIG_PATCHFILE}"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
desc 'Start a Jasig CAS Server instance (requires PORT to be set)'
|
156
|
+
task :start => :prep do
|
157
|
+
exec "cd #{e instance_dir} && exec java -jar start.jar"
|
158
|
+
end
|
159
|
+
|
160
|
+
desc "Wait for all Jasig CAS Server instances in #{scratch_dir} to become ready"
|
161
|
+
task(:waitall) { wait_all(scratch_dir, timeout) }
|
162
|
+
|
163
|
+
desc "Clean up all Jasig CAS Server instances under #{scratch_dir}"
|
164
|
+
task(:cleanall) { clean_all(scratch_dir, 'jasig') }
|
165
|
+
|
166
|
+
desc "Delete #{scratch_dir}"
|
167
|
+
task :delete_scratch_dir do
|
168
|
+
rm_rf scratch_dir
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
private
|
174
|
+
|
175
|
+
alias_method :e, :shellescape
|
176
|
+
|
177
|
+
def verify_checksum(fn, expected)
|
178
|
+
sha = OpenSSL::Digest::SHA256.new
|
179
|
+
|
180
|
+
File.open(fn, 'r') do |f|
|
181
|
+
until f.eof?
|
182
|
+
sha << f.read(65536)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
actual = sha.to_s
|
187
|
+
raise "checksum mismatch: #{actual} != #{expected}" if actual != expected
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
data/test.sh
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
set -xe
|
4
|
+
|
5
|
+
JASIG_PORT=$1
|
6
|
+
CALLBACK_PORT=$2
|
7
|
+
|
8
|
+
if [ -z $CALLBACK_PORT ]; then
|
9
|
+
echo "Usage: $0 [CAS port] [callback port]"
|
10
|
+
exit 1
|
11
|
+
fi
|
12
|
+
|
13
|
+
bundle exec rake castanet:testing:jasig:delete_scratch_dir castanet:testing:callback:delete_scratch_dir
|
14
|
+
bundle exec rake castanet:testing:jasig:download
|
15
|
+
|
16
|
+
PORT=$JASIG_PORT bundle exec rake castanet:testing:jasig:start &
|
17
|
+
JASIG_PID=$!
|
18
|
+
|
19
|
+
PORT=$CALLBACK_PORT bundle exec rake castanet:testing:callback:start &
|
20
|
+
CALLBACK_PID=$!
|
21
|
+
|
22
|
+
sleep 10
|
23
|
+
|
24
|
+
# CAS and the callback should start.
|
25
|
+
RETVAL=bundle exec rake castanet:testing:jasig:waitall castanet:testing:callback:waitall
|
26
|
+
|
27
|
+
# Shut things down.
|
28
|
+
kill -TERM $JASIG_PID $CALLBACK_PID && wait $JASIG_PID $CALLBACK_PID
|
29
|
+
exit $RETVAL
|
metadata
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: castanet-testing
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Yip
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-09-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: foreman
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.63.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.63.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: yard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: json
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rack
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '10.0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '10.0'
|
97
|
+
description:
|
98
|
+
email:
|
99
|
+
- yipdw@northwestern.edu
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- .gitignore
|
105
|
+
- .travis.yml
|
106
|
+
- CHANGELOG
|
107
|
+
- Gemfile
|
108
|
+
- LICENSE
|
109
|
+
- Procfile
|
110
|
+
- README
|
111
|
+
- Rakefile
|
112
|
+
- assets/callback/callback.rb
|
113
|
+
- assets/jasig/jetty.xml.erb
|
114
|
+
- assets/jasig/jetty.xml.patch
|
115
|
+
- assets/test.crt
|
116
|
+
- assets/test.key
|
117
|
+
- castanet-testing.gemspec
|
118
|
+
- lib/castanet/testing.rb
|
119
|
+
- lib/castanet/testing/asset_paths.rb
|
120
|
+
- lib/castanet/testing/callback_server_tasks.rb
|
121
|
+
- lib/castanet/testing/common_tasks.rb
|
122
|
+
- lib/castanet/testing/connection_testing.rb
|
123
|
+
- lib/castanet/testing/jasig_server_tasks.rb
|
124
|
+
- lib/castanet/testing/namespacing.rb
|
125
|
+
- lib/castanet/testing/version.rb
|
126
|
+
- test.sh
|
127
|
+
homepage: ''
|
128
|
+
licenses:
|
129
|
+
- MIT
|
130
|
+
metadata: {}
|
131
|
+
post_install_message:
|
132
|
+
rdoc_options: []
|
133
|
+
require_paths:
|
134
|
+
- lib
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - '>='
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - '>='
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
requirements: []
|
146
|
+
rubyforge_project:
|
147
|
+
rubygems_version: 2.0.6
|
148
|
+
signing_key:
|
149
|
+
specification_version: 4
|
150
|
+
summary: Contains Rake tasks for managing CAS servers in test environments
|
151
|
+
test_files: []
|
152
|
+
has_rdoc:
|