~ubuntu-branches/ubuntu/saucy/juju-core/saucy-proposed

« back to all changes in this revision

Viewing changes to src/launchpad.net/gwacl/x509session_test.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-07-11 17:18:27 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20130711171827-vjqkg40r0dlf7ys2
Tags: 1.11.2-0ubuntu1
* New upstream release.
* Make juju-core the default juju (LP: #1190634):
  - d/control: Add virtual package juju -> juju-core.
  - d/juju-core.postinst.in: Bump priority of alternatives over that of
    python juju packages.
* Enable for all architectures (LP: #1172505):
  - d/control: Version BD on golang-go to >= 2:1.1.1 to ensure CGO
    support for non-x86 archs, make juju-core Arch: any.
  - d/README.source: Dropped - no longer required.
* d/watch: Updated for new upstream tarball naming.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2013 Canonical Ltd.  This software is licensed under the
 
2
// GNU Lesser General Public License version 3 (see the file COPYING).
 
3
 
 
4
package gwacl
 
5
 
 
6
import (
 
7
    "crypto/rand"
 
8
    "crypto/rsa"
 
9
    "crypto/x509"
 
10
    "crypto/x509/pkix"
 
11
    "encoding/pem"
 
12
    "fmt"
 
13
    . "launchpad.net/gocheck"
 
14
    "math/big"
 
15
    "net/http"
 
16
    "os"
 
17
    "time"
 
18
)
 
19
 
 
20
// x509DispatcherFixture records the current x509 dispatcher before a test,
 
21
// and restores it after.  This gives your test the freedom to replace the
 
22
// dispatcher with test doubles, using any of the rig*Dispatcher functions.
 
23
// Call the fixture's SetUpTest/TearDownTest methods before/after your test,
 
24
// or if you have no other setup/teardown methods, just embed the fixture in
 
25
// your test suite.
 
26
type x509DispatcherFixture struct {
 
27
    oldDispatcher func(*x509Session, *X509Request) (*x509Response, error)
 
28
}
 
29
 
 
30
func (suite *x509DispatcherFixture) SetUpTest(c *C) {
 
31
    // Record the original X509 dispatcher.  Will be restored at the end of
 
32
    // each test.
 
33
    suite.oldDispatcher = _X509Dispatcher
 
34
}
 
35
 
 
36
func (suite *x509DispatcherFixture) TearDownTest(c *C) {
 
37
    // Restore old dispatcher.
 
38
    _X509Dispatcher = suite.oldDispatcher
 
39
}
 
40
 
 
41
type x509SessionSuite struct {
 
42
    x509DispatcherFixture
 
43
}
 
44
 
 
45
var _ = Suite(&x509SessionSuite{})
 
46
 
 
47
// Create a cert and pem file in a temporary dir in /tmp and return the
 
48
// names of the files.  The caller is responsible for cleaning up the files.
 
49
func makeX509Certificate() (string, string) {
 
50
    // Code is shamelessly stolen from
 
51
    // http://golang.org/src/pkg/crypto/tls/generate_cert.go
 
52
    priv, err := rsa.GenerateKey(rand.Reader, 1024)
 
53
    if err != nil {
 
54
        panic(fmt.Errorf("Failed to generate rsa key: %v", err))
 
55
    }
 
56
 
 
57
    // Create a template for x509.CreateCertificate.
 
58
    now := time.Now()
 
59
    template := x509.Certificate{
 
60
        SerialNumber: new(big.Int).SetInt64(0),
 
61
        Subject: pkix.Name{
 
62
            CommonName:   "localhost",
 
63
            Organization: []string{"Bogocorp"},
 
64
        },
 
65
        NotBefore:    now.Add(-5 * time.Minute).UTC(),
 
66
        NotAfter:     now.AddDate(1, 0, 0).UTC(), // valid for 1 year.
 
67
        SubjectKeyId: []byte{1, 2, 3, 4},
 
68
        KeyUsage: x509.KeyUsageKeyEncipherment |
 
69
            x509.KeyUsageDigitalSignature,
 
70
    }
 
71
 
 
72
    // Create the certificate itself.
 
73
    derBytes, err := x509.CreateCertificate(
 
74
        rand.Reader, &template, &template, &priv.PublicKey, priv)
 
75
    if err != nil {
 
76
        panic(fmt.Errorf("Failed to generate x509 certificate: %v", err))
 
77
    }
 
78
 
 
79
    // Write the certificate file out.
 
80
    dirname := os.TempDir() + "/" + MakeRandomString(10)
 
81
    os.Mkdir(dirname, 0700)
 
82
    certFile := dirname + "/cert.pem"
 
83
    certOut, err := os.Create(certFile)
 
84
    if err != nil {
 
85
        panic(fmt.Errorf("Failed to create %s: %v", certFile, err))
 
86
    }
 
87
    pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
 
88
    certOut.Close()
 
89
 
 
90
    // Write the key file out.
 
91
    keyFile := dirname + "/key.pem"
 
92
    keyOut, err := os.OpenFile(
 
93
        keyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
 
94
    if err != nil {
 
95
        panic(fmt.Errorf("Failed to create %s: %v", keyFile, err))
 
96
    }
 
97
    pem.Encode(
 
98
        keyOut,
 
99
        &pem.Block{
 
100
            Type:  "RSA PRIVATE KEY",
 
101
            Bytes: x509.MarshalPKCS1PrivateKey(priv)})
 
102
    keyOut.Close()
 
103
 
 
104
    return certFile, keyFile
 
105
}
 
106
 
 
107
func (suite *x509SessionSuite) TestNewX509SessionCreation(c *C) {
 
108
    _, err := newX509Session("subscriptionid", "azure.pem")
 
109
    c.Assert(err, IsNil)
 
110
}
 
111
 
 
112
func (suite *x509SessionSuite) TestComposeURLComposesURLWithRelativePath(c *C) {
 
113
    const subscriptionID = "subscriptionid"
 
114
    const path = "foo/bar"
 
115
    session, err := newX509Session(subscriptionID, "cert.pem")
 
116
    c.Assert(err, IsNil)
 
117
 
 
118
    url := session.composeURL(path)
 
119
 
 
120
    c.Check(url, Matches, AZURE_URL+subscriptionID+"/"+path)
 
121
}
 
122
 
 
123
func (suite *x509SessionSuite) TestComposeURLRejectsAbsolutePath(c *C) {
 
124
    defer func() {
 
125
        err := recover()
 
126
        c.Assert(err, NotNil)
 
127
        c.Check(err, ErrorMatches, ".*absolute.*path.*")
 
128
    }()
 
129
    session, err := newX509Session("subscriptionid", "cert.pem")
 
130
    c.Assert(err, IsNil)
 
131
 
 
132
    // This panics because we're passing an absolute path.
 
133
    session.composeURL("/foo")
 
134
}
 
135
 
 
136
func (suite *x509SessionSuite) TestGetServerErrorProducesServerError(c *C) {
 
137
    msg := "huhwhat"
 
138
    status := http.StatusNotFound
 
139
    session, err := newX509Session("subscriptionid", "azure.pem")
 
140
    c.Assert(err, IsNil)
 
141
 
 
142
    err = session.getServerError(status, []byte{}, msg)
 
143
    c.Assert(err, NotNil)
 
144
 
 
145
    c.Check(err, ErrorMatches, ".*"+msg+".*")
 
146
    serverError := err.(*ServerError)
 
147
    c.Check(serverError.StatusCode(), Equals, status)
 
148
}
 
149
 
 
150
func (suite *x509SessionSuite) TestGetServerErrorLikes20x(c *C) {
 
151
    goodCodes := []int{
 
152
        http.StatusOK,
 
153
        http.StatusNoContent,
 
154
    }
 
155
    session, err := newX509Session("subscriptionid", "azure.pem")
 
156
    c.Assert(err, IsNil)
 
157
 
 
158
    for _, status := range goodCodes {
 
159
        c.Check(session.getServerError(status, []byte{}, ""), IsNil)
 
160
    }
 
161
}
 
162
 
 
163
func (suite *x509SessionSuite) TestGetServerReturnsErrorsForFailures(c *C) {
 
164
    badCodes := []int{
 
165
        http.StatusSwitchingProtocols,
 
166
        http.StatusBadRequest,
 
167
        http.StatusPaymentRequired,
 
168
        http.StatusForbidden,
 
169
        http.StatusGone,
 
170
        http.StatusInternalServerError,
 
171
        http.StatusNotImplemented,
 
172
    }
 
173
    session, err := newX509Session("subscriptionid", "azure.pem")
 
174
    c.Assert(err, IsNil)
 
175
 
 
176
    for _, status := range badCodes {
 
177
        c.Check(session.getServerError(status, []byte{}, ""), NotNil)
 
178
    }
 
179
}
 
180
 
 
181
func (suite *x509SessionSuite) TestGetIssuesRequest(c *C) {
 
182
    subscriptionID := "subscriptionID"
 
183
    uri := "resource"
 
184
    session, err := newX509Session(subscriptionID, "cert.pem")
 
185
    c.Assert(err, IsNil)
 
186
    // Record incoming requests, and have them return a given reply.
 
187
    fixedResponse := x509Response{
 
188
        StatusCode: http.StatusOK,
 
189
        Body:       []byte("Response body"),
 
190
    }
 
191
    rigFixedResponseDispatcher(&fixedResponse)
 
192
    recordedRequests := make([]*X509Request, 0)
 
193
    rigRecordingDispatcher(&recordedRequests)
 
194
 
 
195
    receivedResponse, err := session.get(uri)
 
196
    c.Assert(err, IsNil)
 
197
 
 
198
    c.Assert(len(recordedRequests), Equals, 1)
 
199
    request := recordedRequests[0]
 
200
    c.Check(request.URL, Equals, AZURE_URL+subscriptionID+"/"+uri)
 
201
    c.Check(request.Method, Equals, "GET")
 
202
    c.Check(*receivedResponse, DeepEquals, fixedResponse)
 
203
}
 
204
 
 
205
func (suite *x509SessionSuite) TestGetReportsClientSideError(c *C) {
 
206
    session, err := newX509Session("subscriptionid", "cert.pem")
 
207
    msg := "could not dispatch request"
 
208
    rigFailingDispatcher(fmt.Errorf(msg))
 
209
 
 
210
    body, err := session.get("flop")
 
211
    c.Assert(err, NotNil)
 
212
 
 
213
    c.Check(body, IsNil)
 
214
    c.Check(err, ErrorMatches, ".*"+msg+".*")
 
215
}
 
216
 
 
217
func (suite *x509SessionSuite) TestGetReportsServerSideError(c *C) {
 
218
    session, err := newX509Session("subscriptionid", "cert.pem")
 
219
    fixedResponse := x509Response{
 
220
        StatusCode: http.StatusForbidden,
 
221
        Body:       []byte("Body"),
 
222
    }
 
223
    rigFixedResponseDispatcher(&fixedResponse)
 
224
 
 
225
    response, err := session.get("fail")
 
226
    c.Assert(err, NotNil)
 
227
 
 
228
    serverError := err.(*ServerError)
 
229
    c.Check(serverError.StatusCode(), Equals, fixedResponse.StatusCode)
 
230
    c.Check(*response, DeepEquals, fixedResponse)
 
231
}
 
232
 
 
233
func (suite *x509SessionSuite) TestPostIssuesRequest(c *C) {
 
234
    subscriptionID := "subscriptionID"
 
235
    uri := "resource"
 
236
    requestBody := []byte("Request body")
 
237
    requestContentType := "bogusContentType"
 
238
    session, err := newX509Session(subscriptionID, "cert.pem")
 
239
    c.Assert(err, IsNil)
 
240
    // Record incoming requests, and have them return a given reply.
 
241
    fixedResponse := x509Response{
 
242
        StatusCode: http.StatusOK,
 
243
        Body:       []byte("Response body"),
 
244
    }
 
245
    rigFixedResponseDispatcher(&fixedResponse)
 
246
    recordedRequests := make([]*X509Request, 0)
 
247
    rigRecordingDispatcher(&recordedRequests)
 
248
 
 
249
    receivedResponse, err := session.post(uri, requestBody, requestContentType)
 
250
    c.Assert(err, IsNil)
 
251
 
 
252
    c.Assert(len(recordedRequests), Equals, 1)
 
253
    request := recordedRequests[0]
 
254
    c.Check(request.URL, Equals, AZURE_URL+subscriptionID+"/"+uri)
 
255
    c.Check(request.Method, Equals, "POST")
 
256
    c.Check(request.ContentType, Equals, requestContentType)
 
257
    c.Check(request.Payload, DeepEquals, requestBody)
 
258
    c.Check(*receivedResponse, DeepEquals, fixedResponse)
 
259
}
 
260
 
 
261
func (suite *x509SessionSuite) TestPostReportsClientSideError(c *C) {
 
262
    session, err := newX509Session("subscriptionid", "cert.pem")
 
263
    msg := "could not dispatch request"
 
264
    rigFailingDispatcher(fmt.Errorf(msg))
 
265
 
 
266
    body, err := session.post("flop", []byte("body"), "contentType")
 
267
    c.Assert(err, NotNil)
 
268
 
 
269
    c.Check(body, IsNil)
 
270
    c.Check(err, ErrorMatches, ".*"+msg+".*")
 
271
}
 
272
 
 
273
func (suite *x509SessionSuite) TestPostReportsServerSideError(c *C) {
 
274
    session, err := newX509Session("subscriptionid", "cert.pem")
 
275
    fixedResponse := x509Response{
 
276
        StatusCode: http.StatusForbidden,
 
277
        Body:       []byte("Body"),
 
278
    }
 
279
    rigFixedResponseDispatcher(&fixedResponse)
 
280
 
 
281
    reponse, err := session.post("fail", []byte("request body"), "contentType")
 
282
    c.Assert(err, NotNil)
 
283
 
 
284
    serverError := err.(*ServerError)
 
285
    c.Check(serverError.StatusCode(), Equals, fixedResponse.StatusCode)
 
286
    c.Check(*reponse, DeepEquals, fixedResponse)
 
287
}
 
288
 
 
289
func (suite *x509SessionSuite) TestDeleteIssuesRequest(c *C) {
 
290
    subscriptionID := "subscriptionID"
 
291
    uri := "resource"
 
292
    session, err := newX509Session(subscriptionID, "cert.pem")
 
293
    c.Assert(err, IsNil)
 
294
    // Record incoming requests, and have them return a given reply.
 
295
    fixedResponse := x509Response{StatusCode: http.StatusOK}
 
296
    rigFixedResponseDispatcher(&fixedResponse)
 
297
    recordedRequests := make([]*X509Request, 0)
 
298
    rigRecordingDispatcher(&recordedRequests)
 
299
 
 
300
    response, err := session.delete(uri)
 
301
    c.Assert(err, IsNil)
 
302
 
 
303
    c.Check(*response, DeepEquals, fixedResponse)
 
304
    c.Assert(len(recordedRequests), Equals, 1)
 
305
    request := recordedRequests[0]
 
306
    c.Check(request.URL, Equals, AZURE_URL+subscriptionID+"/"+uri)
 
307
    c.Check(request.Method, Equals, "DELETE")
 
308
}
 
309
 
 
310
func (suite *x509SessionSuite) TestPutIssuesRequest(c *C) {
 
311
    subscriptionID := "subscriptionID"
 
312
    uri := "resource"
 
313
    requestBody := []byte("Request body")
 
314
    session, err := newX509Session(subscriptionID, "cert.pem")
 
315
    c.Assert(err, IsNil)
 
316
    // Record incoming requests, and have them return a given reply.
 
317
    fixedResponse := x509Response{
 
318
        StatusCode: http.StatusOK,
 
319
    }
 
320
    rigFixedResponseDispatcher(&fixedResponse)
 
321
    recordedRequests := make([]*X509Request, 0)
 
322
    rigRecordingDispatcher(&recordedRequests)
 
323
 
 
324
    _, err = session.put(uri, requestBody)
 
325
    c.Assert(err, IsNil)
 
326
 
 
327
    c.Assert(len(recordedRequests), Equals, 1)
 
328
    request := recordedRequests[0]
 
329
    c.Check(request.URL, Equals, AZURE_URL+subscriptionID+"/"+uri)
 
330
    c.Check(request.Method, Equals, "PUT")
 
331
    c.Check(request.Payload, DeepEquals, requestBody)
 
332
}