Merge lp:~pedronis/ubuntu-push/http-ssl into lp:ubuntu-push
- http-ssl
- Merge into trunk
Proposed by
Samuele Pedroni
Status: | Superseded |
---|---|
Proposed branch: | lp:~pedronis/ubuntu-push/http-ssl |
Merge into: | lp:ubuntu-push |
Diff against target: |
864 lines (+252/-206) 20 files modified
client/session/session_test.go (+4/-25) debian/ubuntu-push-client.conf (+4/-0) docs/highlevel.txt (+25/-34) docs/lowlevel.txt (+25/-34) sampleconfigs/dev.json (+1/-1) server/acceptance/acceptance_test.go (+1/-1) server/acceptance/ssl/README (+1/-1) server/acceptance/ssl/testing.cert (+7/-7) server/acceptance/ssl/testing.key (+7/-7) server/acceptance/suites/broadcast.go (+1/-1) server/acceptance/suites/suite.go (+1/-1) server/config_test.go (+12/-11) server/dev/server.go (+2/-2) server/listener/listener.go (+4/-13) server/listener/listener_test.go (+9/-17) server/runner_devices.go (+2/-29) server/runner_http.go (+6/-1) server/runner_test.go (+45/-6) server/tlsconfig.go (+53/-0) testing/tls.go (+42/-15) |
To merge this branch: | bzr merge lp:~pedronis/ubuntu-push/http-ssl |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Push Hackers | Pending | ||
Review via email: mp+233402@code.launchpad.net |
Commit message
- let the http runner serve over tls optionally
- more realistic testing cert/key
- review how we setup tls in tests
Description of the change
- let the http runner serve over tls optionally
- more realistic testing cert/key
- review how we setup tls in tests
To post a comment you must log in.
- 327. By Samuele Pedroni
-
comment tweak
- 328. By Samuele Pedroni
-
fix, thanks verterok
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'client/session/session_test.go' | |||
2 | --- client/session/session_test.go 2014-08-26 16:05:28 +0000 | |||
3 | +++ client/session/session_test.go 2014-09-04 17:51:30 +0000 | |||
4 | @@ -1489,14 +1489,7 @@ | |||
5 | 1489 | 1489 | ||
6 | 1490 | func (cs *clientSessionSuite) TestDialBadServerName(c *C) { | 1490 | func (cs *clientSessionSuite) TestDialBadServerName(c *C) { |
7 | 1491 | // a borked server name | 1491 | // a borked server name |
16 | 1492 | cert, err := tls.X509KeyPair(helpers.TestCertPEMBlock, helpers.TestKeyPEMBlock) | 1492 | lst, err := tls.Listen("tcp", "localhost:0", helpers.TestTLSServerConfig) |
9 | 1493 | c.Assert(err, IsNil) | ||
10 | 1494 | tlsCfg := &tls.Config{ | ||
11 | 1495 | Certificates: []tls.Certificate{cert}, | ||
12 | 1496 | SessionTicketsDisabled: true, | ||
13 | 1497 | } | ||
14 | 1498 | |||
15 | 1499 | lst, err := tls.Listen("tcp", "localhost:0", tlsCfg) | ||
17 | 1500 | c.Assert(err, IsNil) | 1493 | c.Assert(err, IsNil) |
18 | 1501 | // advertise | 1494 | // advertise |
19 | 1502 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 1495 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
20 | @@ -1541,19 +1534,12 @@ | |||
21 | 1541 | 1534 | ||
22 | 1542 | func (cs *clientSessionSuite) TestDialWorks(c *C) { | 1535 | func (cs *clientSessionSuite) TestDialWorks(c *C) { |
23 | 1543 | // happy path thoughts | 1536 | // happy path thoughts |
32 | 1544 | cert, err := tls.X509KeyPair(helpers.TestCertPEMBlock, helpers.TestKeyPEMBlock) | 1537 | lst, err := tls.Listen("tcp", "localhost:0", helpers.TestTLSServerConfig) |
25 | 1545 | c.Assert(err, IsNil) | ||
26 | 1546 | tlsCfg := &tls.Config{ | ||
27 | 1547 | Certificates: []tls.Certificate{cert}, | ||
28 | 1548 | SessionTicketsDisabled: true, | ||
29 | 1549 | } | ||
30 | 1550 | |||
31 | 1551 | lst, err := tls.Listen("tcp", "localhost:0", tlsCfg) | ||
33 | 1552 | c.Assert(err, IsNil) | 1538 | c.Assert(err, IsNil) |
34 | 1553 | // advertise | 1539 | // advertise |
35 | 1554 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 1540 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
36 | 1555 | b, err := json.Marshal(map[string]interface{}{ | 1541 | b, err := json.Marshal(map[string]interface{}{ |
38 | 1556 | "domain": "localhost", | 1542 | "domain": "push-delivery", |
39 | 1557 | "hosts": []string{"nowhere", lst.Addr().String()}, | 1543 | "hosts": []string{"nowhere", lst.Addr().String()}, |
40 | 1558 | }) | 1544 | }) |
41 | 1559 | if err != nil { | 1545 | if err != nil { |
42 | @@ -1649,14 +1635,7 @@ | |||
43 | 1649 | 1635 | ||
44 | 1650 | func (cs *clientSessionSuite) TestDialWorksDirect(c *C) { | 1636 | func (cs *clientSessionSuite) TestDialWorksDirect(c *C) { |
45 | 1651 | // happy path thoughts | 1637 | // happy path thoughts |
54 | 1652 | cert, err := tls.X509KeyPair(helpers.TestCertPEMBlock, helpers.TestKeyPEMBlock) | 1638 | lst, err := tls.Listen("tcp", "localhost:0", helpers.TestTLSServerConfig) |
47 | 1653 | c.Assert(err, IsNil) | ||
48 | 1654 | tlsCfg := &tls.Config{ | ||
49 | 1655 | Certificates: []tls.Certificate{cert}, | ||
50 | 1656 | SessionTicketsDisabled: true, | ||
51 | 1657 | } | ||
52 | 1658 | |||
53 | 1659 | lst, err := tls.Listen("tcp", "localhost:0", tlsCfg) | ||
55 | 1660 | c.Assert(err, IsNil) | 1639 | c.Assert(err, IsNil) |
56 | 1661 | sess, err := NewSession(lst.Addr().String(), dialTestConf, "wah", cs.lvls, cs.log) | 1640 | sess, err := NewSession(lst.Addr().String(), dialTestConf, "wah", cs.lvls, cs.log) |
57 | 1662 | c.Assert(err, IsNil) | 1641 | c.Assert(err, IsNil) |
58 | 1663 | 1642 | ||
59 | === modified file 'debian/ubuntu-push-client.conf' | |||
60 | --- debian/ubuntu-push-client.conf 2014-08-06 14:08:29 +0000 | |||
61 | +++ debian/ubuntu-push-client.conf 2014-09-04 17:51:30 +0000 | |||
62 | @@ -3,6 +3,10 @@ | |||
63 | 3 | start on started unity8 | 3 | start on started unity8 |
64 | 4 | stop on stopping unity8 | 4 | stop on stopping unity8 |
65 | 5 | 5 | ||
66 | 6 | # set the media role for sounds to notifications' role | ||
67 | 7 | env PULSE_PROP="media.role=alert" | ||
68 | 8 | export PULSE_PROP | ||
69 | 9 | |||
70 | 6 | exec /usr/lib/ubuntu-push-client/ubuntu-push-client | 10 | exec /usr/lib/ubuntu-push-client/ubuntu-push-client |
71 | 7 | respawn | 11 | respawn |
72 | 8 | 12 | ||
73 | 9 | 13 | ||
74 | === modified file 'docs/highlevel.txt' | |||
75 | --- docs/highlevel.txt 2014-08-08 09:09:39 +0000 | |||
76 | +++ docs/highlevel.txt 2014-09-04 17:51:30 +0000 | |||
77 | @@ -3,6 +3,8 @@ | |||
78 | 3 | 3 | ||
79 | 4 | :Version: 0.50+ | 4 | :Version: 0.50+ |
80 | 5 | 5 | ||
81 | 6 | .. contents:: | ||
82 | 7 | |||
83 | 6 | Introduction | 8 | Introduction |
84 | 7 | ------------ | 9 | ------------ |
85 | 8 | 10 | ||
86 | @@ -111,8 +113,8 @@ | |||
87 | 111 | Persistent Notification Management | 113 | Persistent Notification Management |
88 | 112 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 114 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
89 | 113 | 115 | ||
92 | 114 | Some notifications are persistent, meaning they don't disappear automatically. For those notifications, there is an API that | 116 | Some notifications are persistent, meaning that, after they are presented, they don't disappear automatically. |
93 | 115 | allows the app to manage them without having to know the underlying details of the platform. | 117 | This API allows the app to manage that type of notifications. |
94 | 116 | 118 | ||
95 | 117 | On each notification there's an optional ``tag`` field, used for this purpose. | 119 | On each notification there's an optional ``tag`` field, used for this purpose. |
96 | 118 | 120 | ||
97 | @@ -192,6 +194,8 @@ | |||
98 | 192 | 194 | ||
99 | 193 | Helpers output has two parts, the postal message (in the "message" key) and a notification to be presented to the user (in the "notification" key). | 195 | Helpers output has two parts, the postal message (in the "message" key) and a notification to be presented to the user (in the "notification" key). |
100 | 194 | 196 | ||
101 | 197 | .. note:: This format **will** change with future versions of the SDK and it **may** be incompatible. | ||
102 | 198 | |||
103 | 195 | Here's a simple example:: | 199 | Here's a simple example:: |
104 | 196 | 200 | ||
105 | 197 | { | 201 | { |
106 | @@ -281,37 +285,27 @@ | |||
107 | 281 | The Ubuntu Push server is located at https://push.ubuntu.com and has a single endpoint: ``/notify``. | 285 | The Ubuntu Push server is located at https://push.ubuntu.com and has a single endpoint: ``/notify``. |
108 | 282 | To notify a user, your application has to do a POST with ``Content-type: application/json``. | 286 | To notify a user, your application has to do a POST with ``Content-type: application/json``. |
109 | 283 | 287 | ||
110 | 288 | .. note:: The contents of the data field are arbitrary. They should be enough for your helper to build | ||
111 | 289 | a notification using it, and decide whether it should be displayed or not. Keep in mind | ||
112 | 290 | that this will be processed by more than one version of the helper, because the user may be using | ||
113 | 291 | an older version of your app. | ||
114 | 292 | |||
115 | 284 | Here is an example of the POST body using all the fields:: | 293 | Here is an example of the POST body using all the fields:: |
116 | 285 | 294 | ||
146 | 286 | { | 295 | { |
147 | 287 | "appid": "com.ubuntu.music_music", | 296 | "appid": "com.ubuntu.music_music", |
148 | 288 | "expire_on": "2014-10-08T14:48:00.000Z", | 297 | "expire_on": "2014-10-08T14:48:00.000Z", |
149 | 289 | "token": "LeA4tRQG9hhEkuhngdouoA==", | 298 | "token": "LeA4tRQG9hhEkuhngdouoA==", |
150 | 290 | "clear_pending": true, | 299 | "clear_pending": true, |
151 | 291 | "replace_tag": "tagname", | 300 | "replace_tag": "tagname", |
152 | 292 | "data": { | 301 | "data": { |
153 | 293 | "message": "foobar", | 302 | "id": 43578, |
154 | 294 | "notification": { | 303 | "timestamp": 1409583746, |
155 | 295 | "card": { | 304 | "serial": 1254, |
156 | 296 | "summary": "yes", | 305 | "sender": "Joe", |
157 | 297 | "body": "hello", | 306 | "snippet": "Hi there!" |
158 | 298 | "popup": true, | 307 | } |
159 | 299 | "persist": true, | 308 | } |
131 | 300 | "timestamp": 1407160197 | ||
132 | 301 | } | ||
133 | 302 | "sound": "buzz.mp3", | ||
134 | 303 | "tag": "foo", | ||
135 | 304 | "vibrate": { | ||
136 | 305 | "pattern": [200, 100], | ||
137 | 306 | "repeat": 2 | ||
138 | 307 | } | ||
139 | 308 | "emblem-counter": { | ||
140 | 309 | "count": 12, | ||
141 | 310 | "visible": true | ||
142 | 311 | } | ||
143 | 312 | } | ||
144 | 313 | } | ||
145 | 314 | } | ||
160 | 315 | 309 | ||
161 | 316 | 310 | ||
162 | 317 | :appid: ID of the application that will receive the notification, as described in the client side documentation. | 311 | :appid: ID of the application that will receive the notification, as described in the client side documentation. |
163 | @@ -320,6 +314,3 @@ | |||
164 | 320 | :clear_pending: Discards all previous pending notifications. Usually in response to getting a "too-many-pending" error. | 314 | :clear_pending: Discards all previous pending notifications. Usually in response to getting a "too-many-pending" error. |
165 | 321 | :replace_tag: If there's a pending notification with the same tag, delete it before queuing this new one. | 315 | :replace_tag: If there's a pending notification with the same tag, delete it before queuing this new one. |
166 | 322 | :data: A JSON object. | 316 | :data: A JSON object. |
167 | 323 | |||
168 | 324 | In this example, data is `what a helper would output <#helper-output-format>`__ but that's not necessarily the case. | ||
169 | 325 | The content of the data field will be passed to the helper application which **has** to produce output in that format. | ||
170 | 326 | 317 | ||
171 | === modified file 'docs/lowlevel.txt' | |||
172 | --- docs/lowlevel.txt 2014-08-08 09:09:39 +0000 | |||
173 | +++ docs/lowlevel.txt 2014-09-04 17:51:30 +0000 | |||
174 | @@ -3,6 +3,8 @@ | |||
175 | 3 | 3 | ||
176 | 4 | :Version: 0.50+ | 4 | :Version: 0.50+ |
177 | 5 | 5 | ||
178 | 6 | .. contents:: | ||
179 | 7 | |||
180 | 6 | Introduction | 8 | Introduction |
181 | 7 | ------------ | 9 | ------------ |
182 | 8 | 10 | ||
183 | @@ -202,8 +204,8 @@ | |||
184 | 202 | Persistent Notification Management | 204 | Persistent Notification Management |
185 | 203 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 205 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
186 | 204 | 206 | ||
189 | 205 | Some notifications are persistent, meaning they don't disappear automatically. For those notifications, there is an API that | 207 | Some notifications are persistent, meaning that, after they are presented, they don't disappear automatically. |
190 | 206 | allows the app to manage them without having to know the underlying details of the platform. | 208 | This API allows the app to manage that type of notifications. |
191 | 207 | 209 | ||
192 | 208 | On each notification there's an optional ``tag`` field, used for this purpose. | 210 | On each notification there's an optional ``tag`` field, used for this purpose. |
193 | 209 | 211 | ||
194 | @@ -286,6 +288,8 @@ | |||
195 | 286 | 288 | ||
196 | 287 | Helpers output has two parts, the postal message (in the "message" key) and a notification to be presented to the user (in the "notification" key). | 289 | Helpers output has two parts, the postal message (in the "message" key) and a notification to be presented to the user (in the "notification" key). |
197 | 288 | 290 | ||
198 | 291 | .. note:: This format **will** change with future versions of the SDK and it **may** be incompatible. | ||
199 | 292 | |||
200 | 289 | Here's a simple example:: | 293 | Here's a simple example:: |
201 | 290 | 294 | ||
202 | 291 | { | 295 | { |
203 | @@ -375,37 +379,27 @@ | |||
204 | 375 | The Ubuntu Push server is located at https://push.ubuntu.com and has a single endpoint: ``/notify``. | 379 | The Ubuntu Push server is located at https://push.ubuntu.com and has a single endpoint: ``/notify``. |
205 | 376 | To notify a user, your application has to do a POST with ``Content-type: application/json``. | 380 | To notify a user, your application has to do a POST with ``Content-type: application/json``. |
206 | 377 | 381 | ||
207 | 382 | .. note:: The contents of the data field are arbitrary. They should be enough for your helper to build | ||
208 | 383 | a notification using it, and decide whether it should be displayed or not. Keep in mind | ||
209 | 384 | that this will be processed by more than one version of the helper, because the user may be using | ||
210 | 385 | an older version of your app. | ||
211 | 386 | |||
212 | 378 | Here is an example of the POST body using all the fields:: | 387 | Here is an example of the POST body using all the fields:: |
213 | 379 | 388 | ||
243 | 380 | { | 389 | { |
244 | 381 | "appid": "com.ubuntu.music_music", | 390 | "appid": "com.ubuntu.music_music", |
245 | 382 | "expire_on": "2014-10-08T14:48:00.000Z", | 391 | "expire_on": "2014-10-08T14:48:00.000Z", |
246 | 383 | "token": "LeA4tRQG9hhEkuhngdouoA==", | 392 | "token": "LeA4tRQG9hhEkuhngdouoA==", |
247 | 384 | "clear_pending": true, | 393 | "clear_pending": true, |
248 | 385 | "replace_tag": "tagname", | 394 | "replace_tag": "tagname", |
249 | 386 | "data": { | 395 | "data": { |
250 | 387 | "message": "foobar", | 396 | "id": 43578, |
251 | 388 | "notification": { | 397 | "timestamp": 1409583746, |
252 | 389 | "card": { | 398 | "serial": 1254, |
253 | 390 | "summary": "yes", | 399 | "sender": "Joe", |
254 | 391 | "body": "hello", | 400 | "snippet": "Hi there!" |
255 | 392 | "popup": true, | 401 | } |
256 | 393 | "persist": true, | 402 | } |
228 | 394 | "timestamp": 1407160197 | ||
229 | 395 | } | ||
230 | 396 | "sound": "buzz.mp3", | ||
231 | 397 | "tag": "foo", | ||
232 | 398 | "vibrate": { | ||
233 | 399 | "pattern": [200, 100], | ||
234 | 400 | "repeat": 2 | ||
235 | 401 | } | ||
236 | 402 | "emblem-counter": { | ||
237 | 403 | "count": 12, | ||
238 | 404 | "visible": true | ||
239 | 405 | } | ||
240 | 406 | } | ||
241 | 407 | } | ||
242 | 408 | } | ||
257 | 409 | 403 | ||
258 | 410 | 404 | ||
259 | 411 | :appid: ID of the application that will receive the notification, as described in the client side documentation. | 405 | :appid: ID of the application that will receive the notification, as described in the client side documentation. |
260 | @@ -414,6 +408,3 @@ | |||
261 | 414 | :clear_pending: Discards all previous pending notifications. Usually in response to getting a "too-many-pending" error. | 408 | :clear_pending: Discards all previous pending notifications. Usually in response to getting a "too-many-pending" error. |
262 | 415 | :replace_tag: If there's a pending notification with the same tag, delete it before queuing this new one. | 409 | :replace_tag: If there's a pending notification with the same tag, delete it before queuing this new one. |
263 | 416 | :data: A JSON object. | 410 | :data: A JSON object. |
264 | 417 | |||
265 | 418 | In this example, data is `what a helper would output <#helper-output-format>`__ but that's not necessarily the case. | ||
266 | 419 | The content of the data field will be passed to the helper application which **has** to produce output in that format. | ||
267 | 420 | 411 | ||
268 | === modified file 'sampleconfigs/dev.json' | |||
269 | --- sampleconfigs/dev.json 2014-07-15 17:14:07 +0000 | |||
270 | +++ sampleconfigs/dev.json 2014-09-04 17:51:30 +0000 | |||
271 | @@ -10,5 +10,5 @@ | |||
272 | 10 | "http_read_timeout": "5s", | 10 | "http_read_timeout": "5s", |
273 | 11 | "http_write_timeout": "5s", | 11 | "http_write_timeout": "5s", |
274 | 12 | "max_notifications_per_app": 25, | 12 | "max_notifications_per_app": 25, |
276 | 13 | "delivery_domain": "localhost" | 13 | "delivery_domain": "pus-delivery" |
277 | 14 | } | 14 | } |
278 | 15 | 15 | ||
279 | === modified file 'server/acceptance/acceptance_test.go' | |||
280 | --- server/acceptance/acceptance_test.go 2014-05-02 09:56:49 +0000 | |||
281 | +++ server/acceptance/acceptance_test.go 2014-09-04 17:51:30 +0000 | |||
282 | @@ -34,7 +34,7 @@ | |||
283 | 34 | cfg := make(map[string]interface{}) | 34 | cfg := make(map[string]interface{}) |
284 | 35 | suites.FillServerConfig(cfg, addr) | 35 | suites.FillServerConfig(cfg, addr) |
285 | 36 | suites.FillHTTPServerConfig(cfg, httpAddr) | 36 | suites.FillHTTPServerConfig(cfg, httpAddr) |
287 | 37 | cfg["delivery_domain"] = "localhost" | 37 | cfg["delivery_domain"] = "push-delivery" |
288 | 38 | return cfg | 38 | return cfg |
289 | 39 | } | 39 | } |
290 | 40 | 40 | ||
291 | 41 | 41 | ||
292 | === modified file 'server/acceptance/ssl/README' | |||
293 | --- server/acceptance/ssl/README 2014-02-21 16:17:28 +0000 | |||
294 | +++ server/acceptance/ssl/README 2014-09-04 17:51:30 +0000 | |||
295 | @@ -3,6 +3,6 @@ | |||
296 | 3 | 3 | ||
297 | 4 | Generated with: | 4 | Generated with: |
298 | 5 | 5 | ||
300 | 6 | go run /usr/lib/go/src/pkg/crypto/tls/generate_cert.go -ca -host localhost -rsa-bits 512 -duration 87600h | 6 | go run /usr/lib/go/src/pkg/crypto/tls/generate_cert.go -ca -host push-delivery -rsa-bits 512 -duration 87600h |
301 | 7 | 7 | ||
302 | 8 | and then renamed. | 8 | and then renamed. |
303 | 9 | 9 | ||
304 | === modified file 'server/acceptance/ssl/testing.cert' | |||
305 | --- server/acceptance/ssl/testing.cert 2014-01-14 15:35:20 +0000 | |||
306 | +++ server/acceptance/ssl/testing.cert 2014-09-04 17:51:30 +0000 | |||
307 | @@ -1,10 +1,10 @@ | |||
308 | 1 | -----BEGIN CERTIFICATE----- | 1 | -----BEGIN CERTIFICATE----- |
309 | 2 | MIIBYzCCAQ+gAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD | 2 | MIIBYzCCAQ+gAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD |
317 | 3 | bzAeFw0xMzEyMTkyMDU1NDNaFw0yMzEyMTcyMDU1NDNaMBIxEDAOBgNVBAoTB0Fj | 3 | bzAeFw0xNDA4MjkxMjQyMDFaFw0yNDA4MjYxMjQyMDFaMBIxEDAOBgNVBAoTB0Fj |
318 | 4 | bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAPw+niki17X2qALE2A2AzE1q5dvK | 4 | bWUgQ28wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA1FT6lkow0eky+Dnj2Z4nTrTF |
319 | 5 | 9CI4OduRtT9IgbFLC6psqAT21NA+QbY17nWSSpyP65zkMkwKXrbDzstwLPkCAwEA | 5 | DgcKOt9Wr4B4gRH1bWmRqScOPxyHA5YodN7O1w8X8sdWko9puf59I1sWWr5LNwID |
320 | 6 | AaNUMFIwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud | 6 | AQABo1IwUDAOBgNVHQ8BAf8EBAMCAKQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYD |
321 | 7 | EwEB/wQFMAMBAf8wGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMAsGCSqGSIb3 | 7 | VR0TAQH/BAUwAwEB/zAYBgNVHREEETAPgg1wdXNoLWRlbGl2ZXJ5MAsGCSqGSIb3 |
322 | 8 | DQEBBQNBAFqiVI+Km2XPSO+pxITaPvhmuzg+XG3l1+2di3gL+HlDobocjBqRctRU | 8 | DQEBBQNBABtWCdMFkhIO8+oM3vugOWle9WJZ1FCRWD+cMl76mI1lhmNF4lvEZG47 |
323 | 9 | YySO32W07acjGJmCHUKpCJuq9X8hpmk= | 9 | xUjekA1+heU39WpOEzZSybrOdiEaGbI= |
324 | 10 | -----END CERTIFICATE----- | 10 | -----END CERTIFICATE----- |
325 | 11 | 11 | ||
326 | === modified file 'server/acceptance/ssl/testing.key' | |||
327 | --- server/acceptance/ssl/testing.key 2014-01-14 15:35:20 +0000 | |||
328 | +++ server/acceptance/ssl/testing.key 2014-09-04 17:51:30 +0000 | |||
329 | @@ -1,9 +1,9 @@ | |||
330 | 1 | -----BEGIN RSA PRIVATE KEY----- | 1 | -----BEGIN RSA PRIVATE KEY----- |
338 | 2 | MIIBPAIBAAJBAPw+niki17X2qALE2A2AzE1q5dvK9CI4OduRtT9IgbFLC6psqAT2 | 2 | MIIBOgIBAAJBANRU+pZKMNHpMvg549meJ060xQ4HCjrfVq+AeIER9W1pkaknDj8c |
339 | 3 | 1NA+QbY17nWSSpyP65zkMkwKXrbDzstwLPkCAwEAAQJAKwXbIBULScP6QA6m8xam | 3 | hwOWKHTeztcPF/LHVpKPabn+fSNbFlq+SzcCAwEAAQJBAIOO+4xu/3yv/rKqO7C0 |
340 | 4 | wgWbkvN41GVWqPafPV32kPBvKwSc+M1e+JR7g3/xPZE7TCELcfYi4yXEHZZI3Pbh | 4 | Oyqa+pVMa1w60R0AfqmKFQTqiTgevM77uqjpW1+t0hpK20nyj6MUIPaL+9kZgp7t |
341 | 5 | oQIhAP/UsgJbsfH1GFv8Y8qGl5l/kmwwkwHhuKvEC87Yur9FAiEA/GlQv3ZfaXnT | 5 | mnECIQDqw79PXSzudf10XGy9ve5bRazINHxQYgJ7FvlTT6JhdQIhAOeJxq9zcKni |
342 | 6 | lcCFT0aL02O0RDiRYyMUG/JAZQJs6CUCIQCHO5SZYIUwxIGK5mCNxxXOAzyQSiD7 | 6 | 69ueO1ualz0hn8w6uHPsG9FlZ8C+7Jh7AiAWJgebjjfZ+4nA+6NKt2uQct9dOA5u |
343 | 7 | hqkKywf+4FvfDQIhALa0TLyqJFom0t7c4iIGAIRc8UlIYQSPiajI64+x9775AiEA | 7 | awC+6ij1ojK4rQIgNEqAbcWDj0qpe8sLms+aEntSjJxCZiPP0IW3XeeApZsCIDwo |
344 | 8 | 0v4fgSK/Rq059zW1753JjuB6aR0Uh+3RqJII4dUR1Wg= | 8 | x+YyxXQWJlf9L5TNYPRo+KFEdk3Cew0lv6QNs+xe |
345 | 9 | -----END RSA PRIVATE KEY----- | 9 | -----END RSA PRIVATE KEY----- |
346 | 10 | 10 | ||
347 | === modified file 'server/acceptance/suites/broadcast.go' | |||
348 | --- server/acceptance/suites/broadcast.go 2014-08-15 09:33:48 +0000 | |||
349 | +++ server/acceptance/suites/broadcast.go 2014-09-04 17:51:30 +0000 | |||
350 | @@ -261,7 +261,7 @@ | |||
351 | 261 | host, err := gh.Get() | 261 | host, err := gh.Get() |
352 | 262 | c.Assert(err, IsNil) | 262 | c.Assert(err, IsNil) |
353 | 263 | expected := &gethosts.Host{ | 263 | expected := &gethosts.Host{ |
355 | 264 | Domain: "localhost", | 264 | Domain: "push-delivery", |
356 | 265 | Hosts: []string{s.ServerAddr}, | 265 | Hosts: []string{s.ServerAddr}, |
357 | 266 | } | 266 | } |
358 | 267 | c.Check(host, DeepEquals, expected) | 267 | c.Check(host, DeepEquals, expected) |
359 | 268 | 268 | ||
360 | === modified file 'server/acceptance/suites/suite.go' | |||
361 | --- server/acceptance/suites/suite.go 2014-08-27 21:19:51 +0000 | |||
362 | +++ server/acceptance/suites/suite.go 2014-09-04 17:51:30 +0000 | |||
363 | @@ -111,7 +111,7 @@ | |||
364 | 111 | } | 111 | } |
365 | 112 | 112 | ||
366 | 113 | func testClientSession(addr string, deviceId, model, imageChannel string, reportPings bool) *acceptance.ClientSession { | 113 | func testClientSession(addr string, deviceId, model, imageChannel string, reportPings bool) *acceptance.ClientSession { |
368 | 114 | tlsConfig, err := kit.MakeTLSConfig("", false, helpers.SourceRelative("../ssl/testing.cert"), "") | 114 | tlsConfig, err := kit.MakeTLSConfig("push-delivery", false, helpers.SourceRelative("../ssl/testing.cert"), "") |
369 | 115 | if err != nil { | 115 | if err != nil { |
370 | 116 | panic(fmt.Sprintf("could not read ssl/testing.cert: %v", err)) | 116 | panic(fmt.Sprintf("could not read ssl/testing.cert: %v", err)) |
371 | 117 | } | 117 | } |
372 | 118 | 118 | ||
373 | === modified file 'server/config_test.go' | |||
374 | --- server/config_test.go 2014-02-10 23:19:08 +0000 | |||
375 | +++ server/config_test.go 2014-09-04 17:51:30 +0000 | |||
376 | @@ -26,6 +26,7 @@ | |||
377 | 26 | . "launchpad.net/gocheck" | 26 | . "launchpad.net/gocheck" |
378 | 27 | 27 | ||
379 | 28 | "launchpad.net/ubuntu-push/config" | 28 | "launchpad.net/ubuntu-push/config" |
380 | 29 | helpers "launchpad.net/ubuntu-push/testing" | ||
381 | 29 | ) | 30 | ) |
382 | 30 | 31 | ||
383 | 31 | type configSuite struct{} | 32 | type configSuite struct{} |
384 | @@ -52,22 +53,22 @@ | |||
385 | 52 | c.Check(cfg.Addr(), Equals, "127.0.0.1:9999") | 53 | c.Check(cfg.Addr(), Equals, "127.0.0.1:9999") |
386 | 53 | } | 54 | } |
387 | 54 | 55 | ||
389 | 55 | func (s *configSuite) TestDevicesParsedConfigLoadFinish(c *C) { | 56 | func (s *configSuite) TestTLSParsedConfigLoadPEMs(c *C) { |
390 | 56 | tmpDir := c.MkDir() | 57 | tmpDir := c.MkDir() |
392 | 57 | cfg := &DevicesParsedConfig{ | 58 | cfg := &TLSParsedConfig{ |
393 | 58 | ParsedKeyPEMFile: "key.key", | 59 | ParsedKeyPEMFile: "key.key", |
394 | 59 | ParsedCertPEMFile: "cert.cert", | 60 | ParsedCertPEMFile: "cert.cert", |
395 | 60 | } | 61 | } |
397 | 61 | err := cfg.FinishLoad(tmpDir) | 62 | err := cfg.LoadPEMs(tmpDir) |
398 | 62 | c.Check(err, ErrorMatches, "reading key_pem_file:.*no such file.*") | 63 | c.Check(err, ErrorMatches, "reading key_pem_file:.*no such file.*") |
400 | 63 | err = ioutil.WriteFile(filepath.Join(tmpDir, "key.key"), []byte("KeY"), os.ModePerm) | 64 | err = ioutil.WriteFile(filepath.Join(tmpDir, "key.key"), helpers.TestKeyPEMBlock, os.ModePerm) |
401 | 64 | c.Assert(err, IsNil) | 65 | c.Assert(err, IsNil) |
403 | 65 | err = cfg.FinishLoad(tmpDir) | 66 | err = cfg.LoadPEMs(tmpDir) |
404 | 66 | c.Check(err, ErrorMatches, "reading cert_pem_file:.*no such file.*") | 67 | c.Check(err, ErrorMatches, "reading cert_pem_file:.*no such file.*") |
411 | 67 | err = ioutil.WriteFile(filepath.Join(tmpDir, "cert.cert"), []byte("CeRt"), os.ModePerm) | 68 | err = ioutil.WriteFile(filepath.Join(tmpDir, "cert.cert"), helpers.TestCertPEMBlock, os.ModePerm) |
412 | 68 | c.Assert(err, IsNil) | 69 | c.Assert(err, IsNil) |
413 | 69 | err = cfg.FinishLoad(tmpDir) | 70 | err = cfg.LoadPEMs(tmpDir) |
414 | 70 | c.Assert(err, IsNil) | 71 | c.Assert(err, IsNil) |
415 | 71 | c.Check(string(cfg.KeyPEMBlock()), Equals, "KeY") | 72 | tlsCfg := cfg.TLSServerConfig() |
416 | 72 | c.Check(string(cfg.CertPEMBlock()), Equals, "CeRt") | 73 | c.Check(tlsCfg.Certificates, HasLen, 1) |
417 | 73 | } | 74 | } |
418 | 74 | 75 | ||
419 | === modified file 'server/dev/server.go' | |||
420 | --- server/dev/server.go 2014-07-08 15:08:52 +0000 | |||
421 | +++ server/dev/server.go 2014-09-04 17:51:30 +0000 | |||
422 | @@ -64,7 +64,7 @@ | |||
423 | 64 | if err != nil { | 64 | if err != nil { |
424 | 65 | server.BootLogFatalf("reading config: %v", err) | 65 | server.BootLogFatalf("reading config: %v", err) |
425 | 66 | } | 66 | } |
427 | 67 | err = cfg.DevicesParsedConfig.FinishLoad(filepath.Dir(cfgFpaths[len(cfgFpaths)-1])) | 67 | err = cfg.DevicesParsedConfig.LoadPEMs(filepath.Dir(cfgFpaths[len(cfgFpaths)-1])) |
428 | 68 | if err != nil { | 68 | if err != nil { |
429 | 69 | server.BootLogFatalf("reading config: %v", err) | 69 | server.BootLogFatalf("reading config: %v", err) |
430 | 70 | } | 70 | } |
431 | @@ -95,7 +95,7 @@ | |||
432 | 95 | }) | 95 | }) |
433 | 96 | }) | 96 | }) |
434 | 97 | handler := api.PanicTo500Handler(mux, logger) | 97 | handler := api.PanicTo500Handler(mux, logger) |
436 | 98 | go server.HTTPServeRunner(nil, handler, &cfg.HTTPServeParsedConfig)() | 98 | go server.HTTPServeRunner(nil, handler, &cfg.HTTPServeParsedConfig, nil)() |
437 | 99 | // listen for device connections | 99 | // listen for device connections |
438 | 100 | server.DevicesRunner(lst, func(conn net.Conn) error { | 100 | server.DevicesRunner(lst, func(conn net.Conn) error { |
439 | 101 | track := session.NewTracker(logger) | 101 | track := session.NewTracker(logger) |
440 | 102 | 102 | ||
441 | === modified file 'server/listener/listener.go' | |||
442 | --- server/listener/listener.go 2014-03-06 19:21:44 +0000 | |||
443 | +++ server/listener/listener.go 2014-09-04 17:51:30 +0000 | |||
444 | @@ -30,10 +30,8 @@ | |||
445 | 30 | type DeviceListenerConfig interface { | 30 | type DeviceListenerConfig interface { |
446 | 31 | // Addr to listen on. | 31 | // Addr to listen on. |
447 | 32 | Addr() string | 32 | Addr() string |
452 | 33 | // TLS key | 33 | // TLS config |
453 | 34 | KeyPEMBlock() []byte | 34 | TLSServerConfig() *tls.Config |
450 | 35 | // TLS cert | ||
451 | 36 | CertPEMBlock() []byte | ||
454 | 37 | } | 35 | } |
455 | 38 | 36 | ||
456 | 39 | // DeviceListener listens and setup sessions from device connections. | 37 | // DeviceListener listens and setup sessions from device connections. |
457 | @@ -52,15 +50,8 @@ | |||
458 | 52 | return nil, err | 50 | return nil, err |
459 | 53 | } | 51 | } |
460 | 54 | } | 52 | } |
470 | 55 | cert, err := tls.X509KeyPair(cfg.CertPEMBlock(), cfg.KeyPEMBlock()) | 53 | tlsCfg := cfg.TLSServerConfig() |
471 | 56 | if err != nil { | 54 | return &DeviceListener{tls.NewListener(lst, tlsCfg)}, nil |
463 | 57 | return nil, err | ||
464 | 58 | } | ||
465 | 59 | tlsCfg := &tls.Config{ | ||
466 | 60 | Certificates: []tls.Certificate{cert}, | ||
467 | 61 | SessionTicketsDisabled: true, | ||
468 | 62 | } | ||
469 | 63 | return &DeviceListener{tls.NewListener(lst, tlsCfg)}, err | ||
472 | 64 | } | 55 | } |
473 | 65 | 56 | ||
474 | 66 | // handleTemporary checks and handles if the error is just a temporary network | 57 | // handleTemporary checks and handles if the error is just a temporary network |
475 | 67 | 58 | ||
476 | === modified file 'server/listener/listener_test.go' | |||
477 | --- server/listener/listener_test.go 2014-08-04 14:47:00 +0000 | |||
478 | +++ server/listener/listener_test.go 2014-09-04 17:51:30 +0000 | |||
479 | @@ -18,7 +18,6 @@ | |||
480 | 18 | 18 | ||
481 | 19 | import ( | 19 | import ( |
482 | 20 | "crypto/tls" | 20 | "crypto/tls" |
483 | 21 | "crypto/x509" | ||
484 | 22 | "net" | 21 | "net" |
485 | 23 | "os/exec" | 22 | "os/exec" |
486 | 24 | "regexp" | 23 | "regexp" |
487 | @@ -68,12 +67,8 @@ | |||
488 | 68 | return cfg.addr | 67 | return cfg.addr |
489 | 69 | } | 68 | } |
490 | 70 | 69 | ||
497 | 71 | func (cfg *testDevListenerCfg) KeyPEMBlock() []byte { | 70 | func (cfg *testDevListenerCfg) TLSServerConfig() *tls.Config { |
498 | 72 | return helpers.TestKeyPEMBlock | 71 | return helpers.TestTLSServerConfig |
493 | 73 | } | ||
494 | 74 | |||
495 | 75 | func (cfg *testDevListenerCfg) CertPEMBlock() []byte { | ||
496 | 76 | return helpers.TestCertPEMBlock | ||
499 | 77 | } | 72 | } |
500 | 78 | 73 | ||
501 | 79 | func (s *listenerSuite) TestDeviceListen(c *C) { | 74 | func (s *listenerSuite) TestDeviceListen(c *C) { |
502 | @@ -130,11 +125,8 @@ | |||
503 | 130 | return err | 125 | return err |
504 | 131 | } | 126 | } |
505 | 132 | 127 | ||
511 | 133 | func testTlsDial(c *C, addr string) (net.Conn, error) { | 128 | func testTlsDial(addr string) (net.Conn, error) { |
512 | 134 | cp := x509.NewCertPool() | 129 | return tls.Dial("tcp", addr, helpers.TestTLSClientConfig) |
508 | 135 | ok := cp.AppendCertsFromPEM((&testDevListenerCfg{}).CertPEMBlock()) | ||
509 | 136 | c.Assert(ok, Equals, true) | ||
510 | 137 | return tls.Dial("tcp", addr, &tls.Config{RootCAs: cp}) | ||
513 | 138 | } | 130 | } |
514 | 139 | 131 | ||
515 | 140 | func testWriteByte(c *C, conn net.Conn, toWrite uint32) { | 132 | func testWriteByte(c *C, conn net.Conn, toWrite uint32) { |
516 | @@ -159,11 +151,11 @@ | |||
517 | 159 | errCh <- lst.AcceptLoop(testSession, s.testlog) | 151 | errCh <- lst.AcceptLoop(testSession, s.testlog) |
518 | 160 | }() | 152 | }() |
519 | 161 | listenerAddr := lst.Addr().String() | 153 | listenerAddr := lst.Addr().String() |
521 | 162 | conn1, err := testTlsDial(c, listenerAddr) | 154 | conn1, err := testTlsDial(listenerAddr) |
522 | 163 | c.Assert(err, IsNil) | 155 | c.Assert(err, IsNil) |
523 | 164 | defer conn1.Close() | 156 | defer conn1.Close() |
524 | 165 | testWriteByte(c, conn1, '1') | 157 | testWriteByte(c, conn1, '1') |
526 | 166 | conn2, err := testTlsDial(c, listenerAddr) | 158 | conn2, err := testTlsDial(listenerAddr) |
527 | 167 | c.Assert(err, IsNil) | 159 | c.Assert(err, IsNil) |
528 | 168 | defer conn2.Close() | 160 | defer conn2.Close() |
529 | 169 | testWriteByte(c, conn2, '2') | 161 | testWriteByte(c, conn2, '2') |
530 | @@ -203,7 +195,7 @@ | |||
531 | 203 | res, err := cmd.Output() | 195 | res, err := cmd.Output() |
532 | 204 | c.Assert(err, IsNil) | 196 | c.Assert(err, IsNil) |
533 | 205 | c.Assert(string(res), Matches, "(?s).*timed out.*") | 197 | c.Assert(string(res), Matches, "(?s).*timed out.*") |
535 | 206 | conn2, err := testTlsDial(c, listenerAddr) | 198 | conn2, err := testTlsDial(listenerAddr) |
536 | 207 | c.Assert(err, IsNil) | 199 | c.Assert(err, IsNil) |
537 | 208 | defer conn2.Close() | 200 | defer conn2.Close() |
538 | 209 | testWriteByte(c, conn2, '2') | 201 | testWriteByte(c, conn2, '2') |
539 | @@ -225,7 +217,7 @@ | |||
540 | 225 | }, s.testlog) | 217 | }, s.testlog) |
541 | 226 | }() | 218 | }() |
542 | 227 | listenerAddr := lst.Addr().String() | 219 | listenerAddr := lst.Addr().String() |
544 | 228 | _, err = testTlsDial(c, listenerAddr) | 220 | _, err = testTlsDial(listenerAddr) |
545 | 229 | c.Assert(err, Not(IsNil)) | 221 | c.Assert(err, Not(IsNil)) |
546 | 230 | lst.Close() | 222 | lst.Close() |
547 | 231 | c.Check(<-errCh, ErrorMatches, ".*use of closed.*") | 223 | c.Check(<-errCh, ErrorMatches, ".*use of closed.*") |
548 | @@ -244,7 +236,7 @@ | |||
549 | 244 | }() | 236 | }() |
550 | 245 | listenerAddr := lst.Addr().String() | 237 | listenerAddr := lst.Addr().String() |
551 | 246 | c.Check(listenerAddr, Equals, foreignLst.Addr().String()) | 238 | c.Check(listenerAddr, Equals, foreignLst.Addr().String()) |
553 | 247 | conn1, err := testTlsDial(c, listenerAddr) | 239 | conn1, err := testTlsDial(listenerAddr) |
554 | 248 | c.Assert(err, IsNil) | 240 | c.Assert(err, IsNil) |
555 | 249 | defer conn1.Close() | 241 | defer conn1.Close() |
556 | 250 | testWriteByte(c, conn1, '1') | 242 | testWriteByte(c, conn1, '1') |
557 | 251 | 243 | ||
558 | === modified file 'server/runner_devices.go' | |||
559 | --- server/runner_devices.go 2014-03-12 12:34:18 +0000 | |||
560 | +++ server/runner_devices.go 2014-09-04 17:51:30 +0000 | |||
561 | @@ -17,7 +17,6 @@ | |||
562 | 17 | package server | 17 | package server |
563 | 18 | 18 | ||
564 | 19 | import ( | 19 | import ( |
565 | 20 | "fmt" | ||
566 | 21 | "net" | 20 | "net" |
567 | 22 | "syscall" | 21 | "syscall" |
568 | 23 | "time" | 22 | "time" |
569 | @@ -36,26 +35,8 @@ | |||
570 | 36 | ParsedSessionQueueSize config.ConfigQueueSize `json:"session_queue_size"` | 35 | ParsedSessionQueueSize config.ConfigQueueSize `json:"session_queue_size"` |
571 | 37 | ParsedBrokerQueueSize config.ConfigQueueSize `json:"broker_queue_size"` | 36 | ParsedBrokerQueueSize config.ConfigQueueSize `json:"broker_queue_size"` |
572 | 38 | // device listener configuration | 37 | // device listener configuration |
593 | 39 | ParsedAddr config.ConfigHostPort `json:"addr"` | 38 | ParsedAddr config.ConfigHostPort `json:"addr"` |
594 | 40 | ParsedKeyPEMFile string `json:"key_pem_file"` | 39 | TLSParsedConfig |
575 | 41 | ParsedCertPEMFile string `json:"cert_pem_file"` | ||
576 | 42 | // private post-processed config | ||
577 | 43 | certPEMBlock []byte | ||
578 | 44 | keyPEMBlock []byte | ||
579 | 45 | } | ||
580 | 46 | |||
581 | 47 | func (cfg *DevicesParsedConfig) FinishLoad(baseDir string) error { | ||
582 | 48 | keyPEMBlock, err := config.LoadFile(cfg.ParsedKeyPEMFile, baseDir) | ||
583 | 49 | if err != nil { | ||
584 | 50 | return fmt.Errorf("reading key_pem_file: %v", err) | ||
585 | 51 | } | ||
586 | 52 | certPEMBlock, err := config.LoadFile(cfg.ParsedCertPEMFile, baseDir) | ||
587 | 53 | if err != nil { | ||
588 | 54 | return fmt.Errorf("reading cert_pem_file: %v", err) | ||
589 | 55 | } | ||
590 | 56 | cfg.keyPEMBlock = keyPEMBlock | ||
591 | 57 | cfg.certPEMBlock = certPEMBlock | ||
592 | 58 | return nil | ||
595 | 59 | } | 40 | } |
596 | 60 | 41 | ||
597 | 61 | func (cfg *DevicesParsedConfig) PingInterval() time.Duration { | 42 | func (cfg *DevicesParsedConfig) PingInterval() time.Duration { |
598 | @@ -78,14 +59,6 @@ | |||
599 | 78 | return cfg.ParsedAddr.HostPort() | 59 | return cfg.ParsedAddr.HostPort() |
600 | 79 | } | 60 | } |
601 | 80 | 61 | ||
602 | 81 | func (cfg *DevicesParsedConfig) KeyPEMBlock() []byte { | ||
603 | 82 | return cfg.keyPEMBlock | ||
604 | 83 | } | ||
605 | 84 | |||
606 | 85 | func (cfg *DevicesParsedConfig) CertPEMBlock() []byte { | ||
607 | 86 | return cfg.certPEMBlock | ||
608 | 87 | } | ||
609 | 88 | |||
610 | 89 | // DevicesRunner returns a function to accept device connections. | 62 | // DevicesRunner returns a function to accept device connections. |
611 | 90 | // If adoptLst is not nil it will be used as the underlying listener, instead | 63 | // If adoptLst is not nil it will be used as the underlying listener, instead |
612 | 91 | // of creating one, wrapped in a TLS layer. | 64 | // of creating one, wrapped in a TLS layer. |
613 | 92 | 65 | ||
614 | === modified file 'server/runner_http.go' | |||
615 | --- server/runner_http.go 2014-03-25 19:02:18 +0000 | |||
616 | +++ server/runner_http.go 2014-09-04 17:51:30 +0000 | |||
617 | @@ -17,6 +17,7 @@ | |||
618 | 17 | package server | 17 | package server |
619 | 18 | 18 | ||
620 | 19 | import ( | 19 | import ( |
621 | 20 | "crypto/tls" | ||
622 | 20 | "net" | 21 | "net" |
623 | 21 | "net/http" | 22 | "net/http" |
624 | 22 | 23 | ||
625 | @@ -32,7 +33,8 @@ | |||
626 | 32 | 33 | ||
627 | 33 | // HTTPServeRunner returns a function to serve HTTP requests. | 34 | // HTTPServeRunner returns a function to serve HTTP requests. |
628 | 34 | // If httpLst is not nil it will be used as the underlying listener. | 35 | // If httpLst is not nil it will be used as the underlying listener. |
630 | 35 | func HTTPServeRunner(httpLst net.Listener, h http.Handler, parsedCfg *HTTPServeParsedConfig) func() { | 36 | // If tlsCfg is not nit server over TLS with the config. |
631 | 37 | func HTTPServeRunner(httpLst net.Listener, h http.Handler, parsedCfg *HTTPServeParsedConfig, tlsCfg *tls.Config) func() { | ||
632 | 36 | if httpLst == nil { | 38 | if httpLst == nil { |
633 | 37 | var err error | 39 | var err error |
634 | 38 | httpLst, err = net.Listen("tcp", parsedCfg.ParsedHTTPAddr.HostPort()) | 40 | httpLst, err = net.Listen("tcp", parsedCfg.ParsedHTTPAddr.HostPort()) |
635 | @@ -46,6 +48,9 @@ | |||
636 | 46 | ReadTimeout: parsedCfg.ParsedHTTPReadTimeout.TimeDuration(), | 48 | ReadTimeout: parsedCfg.ParsedHTTPReadTimeout.TimeDuration(), |
637 | 47 | WriteTimeout: parsedCfg.ParsedHTTPWriteTimeout.TimeDuration(), | 49 | WriteTimeout: parsedCfg.ParsedHTTPWriteTimeout.TimeDuration(), |
638 | 48 | } | 50 | } |
639 | 51 | if tlsCfg != nil { | ||
640 | 52 | httpLst = tls.NewListener(httpLst, tlsCfg) | ||
641 | 53 | } | ||
642 | 49 | return func() { | 54 | return func() { |
643 | 50 | err := srv.Serve(httpLst) | 55 | err := srv.Serve(httpLst) |
644 | 51 | if err != nil { | 56 | if err != nil { |
645 | 52 | 57 | ||
646 | === modified file 'server/runner_test.go' | |||
647 | --- server/runner_test.go 2014-03-25 19:02:18 +0000 | |||
648 | +++ server/runner_test.go 2014-09-04 17:51:30 +0000 | |||
649 | @@ -17,6 +17,7 @@ | |||
650 | 17 | package server | 17 | package server |
651 | 18 | 18 | ||
652 | 19 | import ( | 19 | import ( |
653 | 20 | "crypto/tls" | ||
654 | 20 | "fmt" | 21 | "fmt" |
655 | 21 | "io/ioutil" | 22 | "io/ioutil" |
656 | 22 | "net" | 23 | "net" |
657 | @@ -68,7 +69,7 @@ | |||
658 | 68 | func (s *runnerSuite) TestHTTPServeRunner(c *C) { | 69 | func (s *runnerSuite) TestHTTPServeRunner(c *C) { |
659 | 69 | errCh := make(chan interface{}, 1) | 70 | errCh := make(chan interface{}, 1) |
660 | 70 | h := http.HandlerFunc(testHandle) | 71 | h := http.HandlerFunc(testHandle) |
662 | 71 | runner := HTTPServeRunner(nil, h, &testHTTPServeParsedConfig) | 72 | runner := HTTPServeRunner(nil, h, &testHTTPServeParsedConfig, nil) |
663 | 72 | c.Assert(s.lst, Not(IsNil)) | 73 | c.Assert(s.lst, Not(IsNil)) |
664 | 73 | defer s.lst.Close() | 74 | defer s.lst.Close() |
665 | 74 | c.Check(s.kind, Equals, "http") | 75 | c.Check(s.kind, Equals, "http") |
666 | @@ -89,16 +90,25 @@ | |||
667 | 89 | c.Check(<-errCh, Matches, "accepting http connections:.*closed.*") | 90 | c.Check(<-errCh, Matches, "accepting http connections:.*closed.*") |
668 | 90 | } | 91 | } |
669 | 91 | 92 | ||
670 | 93 | func cert() tls.Certificate { | ||
671 | 94 | cert, err := tls.X509KeyPair(helpers.TestCertPEMBlock, helpers.TestKeyPEMBlock) | ||
672 | 95 | if err != nil { | ||
673 | 96 | panic(err) | ||
674 | 97 | } | ||
675 | 98 | return cert | ||
676 | 99 | } | ||
677 | 100 | |||
678 | 92 | var testDevicesParsedConfig = DevicesParsedConfig{ | 101 | var testDevicesParsedConfig = DevicesParsedConfig{ |
679 | 93 | ParsedPingInterval: config.ConfigTimeDuration{60 * time.Second}, | 102 | ParsedPingInterval: config.ConfigTimeDuration{60 * time.Second}, |
680 | 94 | ParsedExchangeTimeout: config.ConfigTimeDuration{10 * time.Second}, | 103 | ParsedExchangeTimeout: config.ConfigTimeDuration{10 * time.Second}, |
681 | 95 | ParsedBrokerQueueSize: config.ConfigQueueSize(1000), | 104 | ParsedBrokerQueueSize: config.ConfigQueueSize(1000), |
682 | 96 | ParsedSessionQueueSize: config.ConfigQueueSize(10), | 105 | ParsedSessionQueueSize: config.ConfigQueueSize(10), |
683 | 97 | ParsedAddr: "127.0.0.1:0", | 106 | ParsedAddr: "127.0.0.1:0", |
688 | 98 | ParsedKeyPEMFile: "", | 107 | TLSParsedConfig: TLSParsedConfig{ |
689 | 99 | ParsedCertPEMFile: "", | 108 | ParsedKeyPEMFile: "", |
690 | 100 | keyPEMBlock: helpers.TestKeyPEMBlock, | 109 | ParsedCertPEMFile: "", |
691 | 101 | certPEMBlock: helpers.TestCertPEMBlock, | 110 | cert: cert(), |
692 | 111 | }, | ||
693 | 102 | } | 112 | } |
694 | 103 | 113 | ||
695 | 104 | func (s *runnerSuite) TestDevicesRunner(c *C) { | 114 | func (s *runnerSuite) TestDevicesRunner(c *C) { |
696 | @@ -135,7 +145,36 @@ | |||
697 | 135 | lst0, err := net.Listen("tcp", "127.0.0.1:0") | 145 | lst0, err := net.Listen("tcp", "127.0.0.1:0") |
698 | 136 | c.Assert(err, IsNil) | 146 | c.Assert(err, IsNil) |
699 | 137 | defer lst0.Close() | 147 | defer lst0.Close() |
701 | 138 | HTTPServeRunner(lst0, nil, &testHTTPServeParsedConfig) | 148 | HTTPServeRunner(lst0, nil, &testHTTPServeParsedConfig, nil) |
702 | 139 | c.Assert(s.lst, Equals, lst0) | 149 | c.Assert(s.lst, Equals, lst0) |
703 | 140 | c.Check(s.kind, Equals, "http") | 150 | c.Check(s.kind, Equals, "http") |
704 | 141 | } | 151 | } |
705 | 152 | |||
706 | 153 | func (s *runnerSuite) TestHTTPServeRunnerTLS(c *C) { | ||
707 | 154 | errCh := make(chan interface{}, 1) | ||
708 | 155 | h := http.HandlerFunc(testHandle) | ||
709 | 156 | runner := HTTPServeRunner(nil, h, &testHTTPServeParsedConfig, helpers.TestTLSServerConfig) | ||
710 | 157 | c.Assert(s.lst, Not(IsNil)) | ||
711 | 158 | defer s.lst.Close() | ||
712 | 159 | c.Check(s.kind, Equals, "http") | ||
713 | 160 | go func() { | ||
714 | 161 | defer func() { | ||
715 | 162 | errCh <- recover() | ||
716 | 163 | }() | ||
717 | 164 | runner() | ||
718 | 165 | }() | ||
719 | 166 | cli := http.Client{ | ||
720 | 167 | Transport: &http.Transport{ | ||
721 | 168 | TLSClientConfig: helpers.TestTLSClientConfig, | ||
722 | 169 | }, | ||
723 | 170 | } | ||
724 | 171 | resp, err := cli.Get(fmt.Sprintf("https://%s/", s.lst.Addr())) | ||
725 | 172 | c.Assert(err, IsNil) | ||
726 | 173 | defer resp.Body.Close() | ||
727 | 174 | c.Assert(resp.StatusCode, Equals, 200) | ||
728 | 175 | body, err := ioutil.ReadAll(resp.Body) | ||
729 | 176 | c.Assert(err, IsNil) | ||
730 | 177 | c.Check(string(body), Equals, "yay!\n") | ||
731 | 178 | s.lst.Close() | ||
732 | 179 | c.Check(<-errCh, Matches, "accepting http connections:.*closed.*") | ||
733 | 180 | } | ||
734 | 142 | 181 | ||
735 | === added file 'server/tlsconfig.go' | |||
736 | --- server/tlsconfig.go 1970-01-01 00:00:00 +0000 | |||
737 | +++ server/tlsconfig.go 2014-09-04 17:51:30 +0000 | |||
738 | @@ -0,0 +1,53 @@ | |||
739 | 1 | /* | ||
740 | 2 | Copyright 2013-2014 Canonical Ltd. | ||
741 | 3 | |||
742 | 4 | This program is free software: you can redistribute it and/or modify it | ||
743 | 5 | under the terms of the GNU General Public License version 3, as published | ||
744 | 6 | by the Free Software Foundation. | ||
745 | 7 | |||
746 | 8 | This program is distributed in the hope that it will be useful, but | ||
747 | 9 | WITHOUT ANY WARRANTY; without even the implied warranties of | ||
748 | 10 | MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
749 | 11 | PURPOSE. See the GNU General Public License for more details. | ||
750 | 12 | |||
751 | 13 | You should have received a copy of the GNU General Public License along | ||
752 | 14 | with this program. If not, see <http://www.gnu.org/licenses/>. | ||
753 | 15 | */ | ||
754 | 16 | |||
755 | 17 | package server | ||
756 | 18 | |||
757 | 19 | import ( | ||
758 | 20 | "crypto/tls" | ||
759 | 21 | "fmt" | ||
760 | 22 | |||
761 | 23 | "launchpad.net/ubuntu-push/config" | ||
762 | 24 | ) | ||
763 | 25 | |||
764 | 26 | // A TLSParsedConfig holds and can be used to parse a tls server config. | ||
765 | 27 | type TLSParsedConfig struct { | ||
766 | 28 | ParsedKeyPEMFile string `json:"key_pem_file"` | ||
767 | 29 | ParsedCertPEMFile string `json:"cert_pem_file"` | ||
768 | 30 | // private post-processed config | ||
769 | 31 | cert tls.Certificate | ||
770 | 32 | } | ||
771 | 33 | |||
772 | 34 | func (cfg *TLSParsedConfig) LoadPEMs(baseDir string) error { | ||
773 | 35 | keyPEMBlock, err := config.LoadFile(cfg.ParsedKeyPEMFile, baseDir) | ||
774 | 36 | if err != nil { | ||
775 | 37 | return fmt.Errorf("reading key_pem_file: %v", err) | ||
776 | 38 | } | ||
777 | 39 | certPEMBlock, err := config.LoadFile(cfg.ParsedCertPEMFile, baseDir) | ||
778 | 40 | if err != nil { | ||
779 | 41 | return fmt.Errorf("reading cert_pem_file: %v", err) | ||
780 | 42 | } | ||
781 | 43 | cfg.cert, err = tls.X509KeyPair(certPEMBlock, keyPEMBlock) | ||
782 | 44 | return err | ||
783 | 45 | } | ||
784 | 46 | |||
785 | 47 | func (cfg *TLSParsedConfig) TLSServerConfig() *tls.Config { | ||
786 | 48 | tlsCfg := &tls.Config{ | ||
787 | 49 | Certificates: []tls.Certificate{cfg.cert}, | ||
788 | 50 | SessionTicketsDisabled: true, | ||
789 | 51 | } | ||
790 | 52 | return tlsCfg | ||
791 | 53 | } | ||
792 | 0 | 54 | ||
793 | === modified file 'testing/tls.go' | |||
794 | --- testing/tls.go 2014-01-21 21:36:07 +0000 | |||
795 | +++ testing/tls.go 2014-09-04 17:51:30 +0000 | |||
796 | @@ -16,26 +16,53 @@ | |||
797 | 16 | 16 | ||
798 | 17 | package testing | 17 | package testing |
799 | 18 | 18 | ||
801 | 19 | // key&cert generated with go run /usr/lib/go/src/pkg/crypto/tls/generate_cert.go -ca -host localhost -rsa-bits 512 -duration 87600h | 19 | import ( |
802 | 20 | "crypto/tls" | ||
803 | 21 | "crypto/x509" | ||
804 | 22 | ) | ||
805 | 23 | |||
806 | 24 | // key&cert generated with go run /usr/lib/go/src/pkg/crypto/tls/generate_cert.go -ca -host push-delivery -rsa-bits 512 -duration 87600h | ||
807 | 20 | var ( | 25 | var ( |
808 | 21 | TestKeyPEMBlock = []byte(`-----BEGIN RSA PRIVATE KEY----- | 26 | TestKeyPEMBlock = []byte(`-----BEGIN RSA PRIVATE KEY----- |
816 | 22 | MIIBPAIBAAJBAPw+niki17X2qALE2A2AzE1q5dvK9CI4OduRtT9IgbFLC6psqAT2 | 27 | MIIBOgIBAAJBANRU+pZKMNHpMvg549meJ060xQ4HCjrfVq+AeIER9W1pkaknDj8c |
817 | 23 | 1NA+QbY17nWSSpyP65zkMkwKXrbDzstwLPkCAwEAAQJAKwXbIBULScP6QA6m8xam | 28 | hwOWKHTeztcPF/LHVpKPabn+fSNbFlq+SzcCAwEAAQJBAIOO+4xu/3yv/rKqO7C0 |
818 | 24 | wgWbkvN41GVWqPafPV32kPBvKwSc+M1e+JR7g3/xPZE7TCELcfYi4yXEHZZI3Pbh | 29 | Oyqa+pVMa1w60R0AfqmKFQTqiTgevM77uqjpW1+t0hpK20nyj6MUIPaL+9kZgp7t |
819 | 25 | oQIhAP/UsgJbsfH1GFv8Y8qGl5l/kmwwkwHhuKvEC87Yur9FAiEA/GlQv3ZfaXnT | 30 | mnECIQDqw79PXSzudf10XGy9ve5bRazINHxQYgJ7FvlTT6JhdQIhAOeJxq9zcKni |
820 | 26 | lcCFT0aL02O0RDiRYyMUG/JAZQJs6CUCIQCHO5SZYIUwxIGK5mCNxxXOAzyQSiD7 | 31 | 69ueO1ualz0hn8w6uHPsG9FlZ8C+7Jh7AiAWJgebjjfZ+4nA+6NKt2uQct9dOA5u |
821 | 27 | hqkKywf+4FvfDQIhALa0TLyqJFom0t7c4iIGAIRc8UlIYQSPiajI64+x9775AiEA | 32 | awC+6ij1ojK4rQIgNEqAbcWDj0qpe8sLms+aEntSjJxCZiPP0IW3XeeApZsCIDwo |
822 | 28 | 0v4fgSK/Rq059zW1753JjuB6aR0Uh+3RqJII4dUR1Wg= | 33 | x+YyxXQWJlf9L5TNYPRo+KFEdk3Cew0lv6QNs+xe |
823 | 29 | -----END RSA PRIVATE KEY-----`) | 34 | -----END RSA PRIVATE KEY-----`) |
824 | 30 | 35 | ||
825 | 31 | TestCertPEMBlock = []byte(`-----BEGIN CERTIFICATE----- | 36 | TestCertPEMBlock = []byte(`-----BEGIN CERTIFICATE----- |
826 | 32 | MIIBYzCCAQ+gAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD | 37 | MIIBYzCCAQ+gAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD |
834 | 33 | bzAeFw0xMzEyMTkyMDU1NDNaFw0yMzEyMTcyMDU1NDNaMBIxEDAOBgNVBAoTB0Fj | 38 | bzAeFw0xNDA4MjkxMjQyMDFaFw0yNDA4MjYxMjQyMDFaMBIxEDAOBgNVBAoTB0Fj |
835 | 34 | bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAPw+niki17X2qALE2A2AzE1q5dvK | 39 | bWUgQ28wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA1FT6lkow0eky+Dnj2Z4nTrTF |
836 | 35 | 9CI4OduRtT9IgbFLC6psqAT21NA+QbY17nWSSpyP65zkMkwKXrbDzstwLPkCAwEA | 40 | DgcKOt9Wr4B4gRH1bWmRqScOPxyHA5YodN7O1w8X8sdWko9puf59I1sWWr5LNwID |
837 | 36 | AaNUMFIwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud | 41 | AQABo1IwUDAOBgNVHQ8BAf8EBAMCAKQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYD |
838 | 37 | EwEB/wQFMAMBAf8wGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMAsGCSqGSIb3 | 42 | VR0TAQH/BAUwAwEB/zAYBgNVHREEETAPgg1wdXNoLWRlbGl2ZXJ5MAsGCSqGSIb3 |
839 | 38 | DQEBBQNBAFqiVI+Km2XPSO+pxITaPvhmuzg+XG3l1+2di3gL+HlDobocjBqRctRU | 43 | DQEBBQNBABtWCdMFkhIO8+oM3vugOWle9WJZ1FCRWD+cMl76mI1lhmNF4lvEZG47 |
840 | 39 | YySO32W07acjGJmCHUKpCJuq9X8hpmk= | 44 | xUjekA1+heU39WpOEzZSybrOdiEaGbI= |
841 | 40 | -----END CERTIFICATE-----`) | 45 | -----END CERTIFICATE-----`) |
842 | 41 | ) | 46 | ) |
843 | 47 | |||
844 | 48 | // test tls server config | ||
845 | 49 | var TestTLSServerConfig, TestTLSClientConfig *tls.Config | ||
846 | 50 | |||
847 | 51 | func init() { | ||
848 | 52 | cert, err := tls.X509KeyPair(TestCertPEMBlock, TestKeyPEMBlock) | ||
849 | 53 | if err != nil { | ||
850 | 54 | panic(err) | ||
851 | 55 | } | ||
852 | 56 | TestTLSServerConfig = &tls.Config{ | ||
853 | 57 | Certificates: []tls.Certificate{cert}, | ||
854 | 58 | } | ||
855 | 59 | cp := x509.NewCertPool() | ||
856 | 60 | ok := cp.AppendCertsFromPEM(TestCertPEMBlock) | ||
857 | 61 | if !ok { | ||
858 | 62 | panic("failed to parse test cert") | ||
859 | 63 | } | ||
860 | 64 | TestTLSClientConfig = &tls.Config{ | ||
861 | 65 | RootCAs: cp, | ||
862 | 66 | ServerName: "push-delivery", | ||
863 | 67 | } | ||
864 | 68 | } |