signers

package
v0.0.0-...-458fca8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 22, 2023 License: MIT Imports: 13 Imported by: 4

Documentation

Index

Constants

This section is empty.

Variables

View Source
var CompatFixtures []*CompatibilityTestFixture = []*CompatibilityTestFixture{
	&CompatibilityTestFixture{
		TestName: "Identify a v2 signature",
		Request: &http.Request{
			Method: "GET",
			Header: MakeHeader(map[string][]string{
				"X-Authorization-Timestamp": []string{"1432075982"},
				"Authorization":             []string{`acquia-http-hmac realm="Pipet%20service",id="efdde334-fe7b-11e4-a322-1697f925ec7b",nonce="d1954337-5319-4821-8427-115542e08d10",version="2.0",headers="",signature="MRlPr/Z1WQY2sMthcaEqETRMw4gPYXlPcTpaLWS2gcc="`},
			}),
			Host: "example.acquiapipet.net",
			URL:  SilentURLParse("https://example.acquiapipet.net/v1.0/task-status/133?limit=10"),
		},
		SecretKey:  "W5PeGMxSItNerkNFqQMfYiJvH14WzVJMy54CPoTAYoI=",
		SystemTime: 1432075982,
		Digest:     sha256.New,
		Expected:   "MRlPr/Z1WQY2sMthcaEqETRMw4gPYXlPcTpaLWS2gcc=",
	},
	&CompatibilityTestFixture{
		TestName: "Identify a v1 signature",
		Request: &http.Request{
			Method: "POST",
			Body:   MakeBody("test content"),
			Header: MakeHeader(map[string][]string{
				"Authorization": []string{"Acquia efdde334-fe7b-11e4-a322-1697f925ec7b:6DQcBYwaKdhRm/eNBKIN2jM8HF8="},
				"Content-Type":  []string{"text/plain"},
				"Date":          []string{"Fri, 19 Mar 1982 00:00:04 GMT"},
			}),
			URL: SilentURLParse("http://example.com/resource/1?key=value"),
		},
		SecretKey:  "secret-key",
		SystemTime: 1432075982,
		Digest:     sha1.New,
		Expected:   "6DQcBYwaKdhRm/eNBKIN2jM8HF8=",
	},
	&CompatibilityTestFixture{
		TestName: "Fail to identify an unimplemented (oauth) signature",
		Request: &http.Request{
			Method: "POST",
			Body:   MakeBody("test content"),
			Header: MakeHeader(map[string][]string{
				"Authorization": []string{`OAuth oauth_consumer_key="xvz1evFS4wEEPTGEFPHBog",oauth_nonce="kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg",oauth_signature="tnnArxj06cWHq44gCs1OSKk%2FjLY%3D",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1318622958",oauth_token="370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb",oauth_version="1.0"`},
				"Content-Type":  []string{"text/plain"},
				"Date":          []string{"Fri, 19 Mar 1982 00:00:04 GMT"},
			}),
			URL: SilentURLParse("http://example.com/resource/1?key=value"),
		},
		SecretKey:  "secret-key",
		SystemTime: 1432075982,
		Digest:     sha1.New,
		Expected:   "",
	},
}
View Source
var Fixtures []*TestFixture = []*TestFixture{
	&TestFixture{
		TestName:   "v1 - simple GET request - invalid header in v2",
		SystemTime: 1432075982,
		Digest:     sha1.New,
		Expected: map[string]string{
			"v1": "7Tq3+JP3lAu4FoJz81XEx5+qfOc=",
		},
		Request: &http.Request{
			Method: "GET",
			URL:    SilentURLParse("http://example.com/resource/1?key=value"),
			Header: MakeHeader(map[string][]string{}),
		},
		AuthHeaders: map[string]string{
			"id": "efdde334-fe7b-11e4-a322-1697f925ec7b",
		},
		SecretKey: "secret-key",
		ErrorType: map[string]ErrorType{
			"v2": ErrorTypeInvalidAuthHeader,
		},
		ExpectedHeader: map[string]string{
			"v1": "Acquia efdde334-fe7b-11e4-a322-1697f925ec7b:7Tq3+JP3lAu4FoJz81XEx5+qfOc=",
		},
	},
	&TestFixture{
		TestName:   "v1 - valid request without additional signed headers - invalid header in v2",
		SystemTime: 1432075982,
		Digest:     sha1.New,
		Expected: map[string]string{
			"v1": "6DQcBYwaKdhRm/eNBKIN2jM8HF8=",
		},
		Request: &http.Request{
			Method: "POST",
			Body:   MakeBody("test content"),
			Header: MakeHeader(map[string][]string{
				"Content-Type": []string{"text/plain"},
				"Date":         []string{"Fri, 19 Mar 1982 00:00:04 GMT"},
			}),
			URL: SilentURLParse("http://example.com/resource/1?key=value"),
		},
		AuthHeaders: map[string]string{
			"id": "efdde334-fe7b-11e4-a322-1697f925ec7b",
		},
		SecretKey: "secret-key",
		ErrorType: map[string]ErrorType{
			"v2": ErrorTypeInvalidAuthHeader,
		},
		ExpectedHeader: map[string]string{
			"v1": "Acquia efdde334-fe7b-11e4-a322-1697f925ec7b:6DQcBYwaKdhRm/eNBKIN2jM8HF8=",
		},
	},
	&TestFixture{
		TestName:   "v1 - valid request with additional signed headers - invalid header in v2",
		SystemTime: 1432075982,
		Digest:     sha1.New,
		Expected: map[string]string{
			"v1": "QRMtvnGmlP1YbaTwpWyB/6A8dRU=",
		},
		Request: &http.Request{
			Method: "POST",
			Body:   MakeBody("test content"),
			Header: MakeHeader(map[string][]string{
				"Content-Type": []string{"text/plain"},
				"Date":         []string{"Fri, 19 Mar 1982 00:00:04 GMT"},
				"Custom1":      []string{"Value1"},
			}),
			URL: SilentURLParse("http://example.com/resource/1?key=value"),
		},
		AuthHeaders: map[string]string{
			"headers": "Custom1",
			"id":      "efdde334-fe7b-11e4-a322-1697f925ec7b",
		},
		SecretKey: "secret-key",
		ErrorType: map[string]ErrorType{
			"v2": ErrorTypeInvalidAuthHeader,
		},
		ExpectedHeader: map[string]string{},
	},
	&TestFixture{
		TestName:   "v2 - valid GET request 2",
		SystemTime: 1432075982,
		Digest:     sha256.New,
		Expected: map[string]string{
			"v2": "1Ku5UroiW1knVP6GH4l7Z4IuQSRxZO2gp/e5yhapv1s=",
		},
		Request: &http.Request{
			Method: "GET",
			Header: MakeHeader(map[string][]string{
				"X-Authorization-Timestamp": []string{"1432075982"},
			}),
			Host: "example.acquiapipet.net",
			URL:  SilentURLParse("https://example.acquiapipet.net/v1.0/task-status/145?limit=1"),
		},
		AuthHeaders: map[string]string{
			"realm":   "Pipet service",
			"id":      "615d6517-1cea-4aa3-b48e-96d83c16c4dd",
			"nonce":   "24c0c836-4f6c-4ed6-a6b0-e091d75ea19d",
			"version": "2.0",
		},
		SecretKey: "TXkgU2VjcmV0IEtleSBUaGF0IGlzIFZlcnkgU2VjdXJl",
		Response: &ResponseFixture{
			Expected: map[string]string{
				"v2": "C98MEJHnQSNiYCxmI4CxJegO62sGZdzEEiSXgSIoxlo=",
			},
			Response: PrepareResponseWriter(`{"id": 145, "status": "in-progress"}`),
		},
		ErrorType: map[string]ErrorType{},
		ExpectedHeader: map[string]string{
			"v2": `acquia-http-hmac id="615d6517-1cea-4aa3-b48e-96d83c16c4dd",nonce="24c0c836-4f6c-4ed6-a6b0-e091d75ea19d",realm="Pipet%20service",signature="1Ku5UroiW1knVP6GH4l7Z4IuQSRxZO2gp/e5yhapv1s=",version="2.0"`,
		},
	},
	&TestFixture{
		TestName:   "v2 - valid GET request 3",
		SystemTime: 1432075982,
		Digest:     sha256.New,
		Expected: map[string]string{
			"v2": "yoHiYvx79ssSDIu3+OldpbFs8RsjrMXgRoM89d5t+zA=",
		},
		Request: &http.Request{
			Method: "GET",
			Header: MakeHeader(map[string][]string{
				"X-Authorization-Timestamp": []string{"1432075982"},
				"X-Custom-Signer1":          []string{"custom-1"},
				"X-Custom-Signer2":          []string{"custom-2"},
			}),
			Host: "example.pipeline.io",
			URL:  SilentURLParse("https://example.pipeline.io/api/v1/ci/pipelines"),
		},
		AuthHeaders: map[string]string{
			"realm":   "CIStore",
			"id":      "e7fe97fa-a0c8-4a42-ab8e-2c26d52df059",
			"nonce":   "a9938d07-d9f0-480c-b007-f1e956bcd027",
			"headers": "X-Custom-Signer1;X-Custom-Signer2",
			"version": "2.0",
		},
		SecretKey: "bXlzZWNyZXRzZWNyZXR0aGluZ3Rva2VlcA==",
		Response: &ResponseFixture{
			Expected: map[string]string{
				"v2": "cUDFSS5tN5vBBS7orIfUag8jhkaGouBb/o8fstUvTF8=",
			},
			Response: PrepareResponseWriter(`[{"pipeline_id":"39b5d58d-0a8f-437d-8dd6-4da50dcc87b7","sitename":"enterprise-g1:sfwiptravis","name":"pipeline.yml","last_job_id":"810e4344-1bed-4fd0-a642-1ba17eb996d5","last_branch":"validate-yaml","last_requested":"2016-03-25T20:26:39.000Z","last_finished":null,"last_status":"succeeded","last_duration":null}]`),
		},
		ErrorType: map[string]ErrorType{},
		ExpectedHeader: map[string]string{
			"v2": `acquia-http-hmac headers="X-Custom-Signer1%3BX-Custom-Signer2",id="e7fe97fa-a0c8-4a42-ab8e-2c26d52df059",nonce="a9938d07-d9f0-480c-b007-f1e956bcd027",realm="CIStore",signature="yoHiYvx79ssSDIu3+OldpbFs8RsjrMXgRoM89d5t+zA=",version="2.0"`,
		},
	},
	&TestFixture{
		TestName:   "v2 - valid GET request",
		SystemTime: 1432075982,
		Digest:     sha256.New,
		Expected: map[string]string{
			"v2": "MRlPr/Z1WQY2sMthcaEqETRMw4gPYXlPcTpaLWS2gcc=",
		},
		Request: &http.Request{
			Method: "GET",
			Header: MakeHeader(map[string][]string{
				"X-Authorization-Timestamp": []string{"1432075982"},
			}),
			Host: "example.acquiapipet.net",
			URL:  SilentURLParse("https://example.acquiapipet.net/v1.0/task-status/133?limit=10"),
		},
		AuthHeaders: map[string]string{
			"realm":   "Pipet service",
			"id":      "efdde334-fe7b-11e4-a322-1697f925ec7b",
			"nonce":   "d1954337-5319-4821-8427-115542e08d10",
			"version": "2.0",
		},
		SecretKey: "W5PeGMxSItNerkNFqQMfYiJvH14WzVJMy54CPoTAYoI=",
		Response: &ResponseFixture{
			Expected: map[string]string{
				"v2": "M4wYp1MKvDpQtVOnN7LVt9L8or4pKyVLhfUFVJxHemU=",
			},
			Response: PrepareResponseWriter(`{"id": 133, "status": "done"}`),
		},
		ErrorType: map[string]ErrorType{},
		ExpectedHeader: map[string]string{
			"v2": `acquia-http-hmac id="efdde334-fe7b-11e4-a322-1697f925ec7b",nonce="d1954337-5319-4821-8427-115542e08d10",realm="Pipet%20service",signature="MRlPr/Z1WQY2sMthcaEqETRMw4gPYXlPcTpaLWS2gcc=",version="2.0"`,
		},
	},
	&TestFixture{
		TestName:   "v2 - valid POST request",
		SystemTime: 1432075982,
		Digest:     sha256.New,
		Expected: map[string]string{
			"v2": "XDBaXgWFCY3aAgQvXyGXMbw9Vds2WPKJe2yP+1eXQgM=",
		},
		Request: &http.Request{
			Method:        "POST",
			Body:          MakeBody("{\"method\":\"hi.bob\",\"params\":[\"5\",\"4\",\"8\"]}"),
			ContentLength: int64(len("{\"method\":\"hi.bob\",\"params\":[\"5\",\"4\",\"8\"]}")),
			Header: MakeHeader(map[string][]string{
				"X-Authorization-Timestamp":      []string{"1432075982"},
				"X-Authorization-Content-SHA256": []string{"6paRNxUA7WawFxJpRp4cEixDjHq3jfIKX072k9slalo="},
				"Content-Type":                   []string{"application/json"},
			}),
			Host: "example.acquiapipet.net",
			URL:  SilentURLParse("https://example.acquiapipet.net/v1.0/task/"),
		},
		AuthHeaders: map[string]string{
			"realm":   "Pipet service",
			"id":      "efdde334-fe7b-11e4-a322-1697f925ec7b",
			"nonce":   "d1954337-5319-4821-8427-115542e08d10",
			"version": "2.0",
		},
		SecretKey: "W5PeGMxSItNerkNFqQMfYiJvH14WzVJMy54CPoTAYoI=",
		Response: &ResponseFixture{
			Expected: map[string]string{
				"v2": "LusIUHmqt9NOALrQ4N4MtXZEFE03MjcDjziK+vVqhvQ=",
			},
			Response: PrepareResponseWriter(``),
		},
		ErrorType: map[string]ErrorType{},
		ExpectedHeader: map[string]string{
			"v2": `acquia-http-hmac id="efdde334-fe7b-11e4-a322-1697f925ec7b",nonce="d1954337-5319-4821-8427-115542e08d10",realm="Pipet%20service",signature="XDBaXgWFCY3aAgQvXyGXMbw9Vds2WPKJe2yP+1eXQgM=",version="2.0"`,
		},
	},
	&TestFixture{
		TestName:   "v2 - valid POST request for register endpoint",
		SystemTime: 1449578521,
		Digest:     sha256.New,
		Expected: map[string]string{
			"v2": "4VtBHjqrdDeYrJySoJVDUHpN9u3vyTsyOLz4chezi98=",
		},
		Request: &http.Request{
			Method:        "POST",
			Body:          MakeBody("{\"method\":\"hi.bob\",\"params\":[\"5\",\"4\",\"8\"]}"),
			ContentLength: int64(len("{\"method\":\"hi.bob\",\"params\":[\"5\",\"4\",\"8\"]}")),
			Header: MakeHeader(map[string][]string{
				"X-Authorization-Timestamp":      []string{"1449578521"},
				"X-Authorization-Content-SHA256": []string{"6paRNxUA7WawFxJpRp4cEixDjHq3jfIKX072k9slalo="},
				"Content-Type":                   []string{"application/json"},
			}),
			Host: "54.154.147.142:3000",
			URL:  SilentURLParse("http://54.154.147.142:3000/register"),
		},
		AuthHeaders: map[string]string{
			"realm":   "Plexus",
			"id":      "f0d16792-cdc9-4585-a5fd-bae3d898d8c5",
			"nonce":   "64d02132-40bf-4fce-85bf-3f1bb1bfe7dd",
			"version": "2.0",
		},
		SecretKey: "eox4TsBBPhpi737yMxpdBbr3sgg/DEC4m47VXO0B8qJLsbdMsmN47j/ZF/EFpyUKtAhm0OWXMGaAjRaho7/93Q==",
		ErrorType: map[string]ErrorType{},
		ExpectedHeader: map[string]string{
			"v2": `acquia-http-hmac id="f0d16792-cdc9-4585-a5fd-bae3d898d8c5",nonce="64d02132-40bf-4fce-85bf-3f1bb1bfe7dd",realm="Plexus",signature="4VtBHjqrdDeYrJySoJVDUHpN9u3vyTsyOLz4chezi98=",version="2.0"`,
		},
	},
	&TestFixture{
		TestName:   "v2 - valid POST request with signed headers",
		SystemTime: 1449578521,
		Digest:     sha256.New,
		Expected: map[string]string{
			"v2": "0duvqeMauat7pTULg3EgcSmBjrorrcRkGKxRDtZEa1c=",
		},
		Request: &http.Request{
			Method:        "POST",
			Body:          MakeBody(`{"cloud_endpoint":"https://cloudapi.acquia.com/v1","cloud_user":"example@acquia.com","cloud_pass":"password","branch":"validate"}`),
			ContentLength: int64(len(`{"cloud_endpoint":"https://cloudapi.acquia.com/v1","cloud_user":"example@acquia.com","cloud_pass":"password","branch":"validate"}`)),
			Header: MakeHeader(map[string][]string{
				"X-Authorization-Timestamp":      []string{"1449578521"},
				"X-Authorization-Content-SHA256": []string{"2YGTI4rcSnOEfd7hRwJzQ2OuJYqAf7jzyIdcBXCGreQ="},
				"Content-Type":                   []string{"application/json"},
				"X-Custom-Signer1":               []string{"custom-1"},
				"X-Custom-Signer2":               []string{"custom-2"},
			}),
			Host: "example.pipeline.io",
			URL:  SilentURLParse("https://example.pipeline.io/api/v1/ci/pipelines/39b5d58d-0a8f-437d-8dd6-4da50dcc87b7/start"),
		},
		AuthHeaders: map[string]string{
			"realm":   "CIStore",
			"id":      "e7fe97fa-a0c8-4a42-ab8e-2c26d52df059",
			"nonce":   "a9938d07-d9f0-480c-b007-f1e956bcd027",
			"headers": "X-Custom-Signer1;X-Custom-Signer2",
			"version": "2.0",
		},
		SecretKey: "bXlzZWNyZXRzZWNyZXR0aGluZ3Rva2VlcA==",
		Response: &ResponseFixture{
			Expected: map[string]string{
				"v2": "SlOYi3pUZADkzU9wEv7kw3hmxjlEyMqBONFEVd7iDbM=",
			},
			Response: PrepareResponseWriter(`"57674bb1-f2ce-4d0f-bfdc-736a78aa027a"`),
		},
		ErrorType: map[string]ErrorType{},
		ExpectedHeader: map[string]string{
			"v2": `acquia-http-hmac headers="X-Custom-Signer1%3BX-Custom-Signer2",id="e7fe97fa-a0c8-4a42-ab8e-2c26d52df059",nonce="a9938d07-d9f0-480c-b007-f1e956bcd027",realm="CIStore",signature="0duvqeMauat7pTULg3EgcSmBjrorrcRkGKxRDtZEa1c=",version="2.0"`,
		},
	},
	&TestFixture{
		TestName:   "v2 - request with missing timestamp",
		SystemTime: 1432075982,
		Digest:     sha256.New,
		Expected:   map[string]string{},
		Request: &http.Request{
			Method: "POST",
			Body:   MakeBody("{\"method\":\"hi.bob\",\"params\":[\"5\",\"4\",\"8\"]}"),
			Header: MakeHeader(map[string][]string{
				"X-Authorization-Content-SHA256": []string{"6paRNxUA7WawFxJpRp4cEixDjHq3jfIKX072k9slalo="},
				"Content-Type":                   []string{"application/json"},
			}),
			Host: "example.acquiapipet.net",
			URL:  SilentURLParse("https://example.acquiapipet.net/v1.0/task/"),
		},
		AuthHeaders: map[string]string{
			"realm":   "Pipet service",
			"id":      "efdde334-fe7b-11e4-a322-1697f925ec7b",
			"nonce":   "d1954337-5319-4821-8427-115542e08d10",
			"version": "2.0",
		},
		SecretKey: "W5PeGMxSItNerkNFqQMfYiJvH14WzVJMy54CPoTAYoI=",
		ErrorType: map[string]ErrorType{
			"v2": ErrorTypeMissingRequiredHeader,
		},
		ExpectedHeader: map[string]string{},
	},

	&TestFixture{
		TestName:   "v2 - outdated keypair (non-b64 encoded secret key)",
		SystemTime: 1432075982,
		Digest:     sha256.New,
		Expected:   map[string]string{},
		Request: &http.Request{
			Method: "POST",
			Body:   MakeBody("{\"method\":\"hi.bob\",\"params\":[\"5\",\"4\",\"8\"]}"),
			Header: MakeHeader(map[string][]string{
				"X-Authorization-Timestamp":      []string{"1432075982"},
				"X-Authorization-Content-SHA256": []string{"6paRNxUA7WawFxJpRp4cEixDjHq3jfIKX072k9slalo="},
				"Content-Type":                   []string{"application/json"},
			}),
			Host: "example.acquiapipet.net",
			URL:  SilentURLParse("https://example.acquiapipet.net/v1.0/task/"),
		},
		AuthHeaders: map[string]string{
			"realm":   "Pipet service",
			"id":      "efdde334-fe7b-11e4-a322-1697f925ec7b",
			"nonce":   "d1954337-5319-4821-8427-115542e08d10",
			"version": "2.0",
		},
		SecretKey: "this is a useless secret key for v2 authentication",
		ErrorType: map[string]ErrorType{
			"v2": ErrorTypeOutdatedKeypair,
		},
		ExpectedHeader: map[string]string{},
	},
}

Functions

func GetErrorTypeText

func GetErrorTypeText(e ErrorType) string

func Logf

func Logf(format string, args ...interface{})

func MakeBody

func MakeBody(content string) io.ReadCloser

func MakeHeader

func MakeHeader(m map[string][]string) http.Header

func NormalizedHeaderName

func NormalizedHeaderName(key string) string

func Now

func Now() time.Time

func OverrideClock

func OverrideClock(timestamp int64)

func Path

func Path(u *url.URL) string

func ReadBody

func ReadBody(r *http.Request) ([]byte, error)

func ReadResponseBody

func ReadResponseBody(r *http.Response) ([]byte, error)

func SilentURLParse

func SilentURLParse(uri string) *url.URL

Types

type AuthenticationError

type AuthenticationError struct {
	Message    string
	HttpStatus int
	ErrorType  ErrorType
}

AuthenticationError no longer implements the error interface because: - go is dumb - the people behind go are illogical bastards - and i'm also dumb for repeatedly falling into the trap the two aforementioned things lay me No, it won't ever implement error. Not until there is a unified way to check for nils in Go. Trust me. It's better this way. One day you'll thank me for it. You'll never know what it's like to fall into the trap set by this four times and waste 32 perfectly fine manhours on it.

func Errorf

func Errorf(status int, errtype ErrorType, format string, args ...interface{}) *AuthenticationError

func (*AuthenticationError) ToError

func (a *AuthenticationError) ToError() error

Here you go.

type Clock

type Clock interface {
	Now() time.Time
}

type CompatibilityTestFixture

type CompatibilityTestFixture struct {
	TestName   string
	Digest     func() hash.Hash
	Request    *http.Request
	SecretKey  string
	SystemTime int64
	Expected   string
}

type Digester

type Digester struct {
	Digest func() hash.Hash
}

type ErrorType

type ErrorType int
const (
	ErrorTypeNoError ErrorType = iota
	ErrorTypeUnknown
	ErrorTypeUnknownSignatureType
	ErrorTypeTimestampRangeError
	ErrorTypeMissingRequiredHeader
	ErrorTypeInvalidRequiredHeader
	ErrorTypeInvalidAuthHeader
	ErrorTypeOutdatedKeypair
	ErrorTypeInternalError
	ErrorTypeSignatureMismatch
)

type Identifiable

type Identifiable struct {
	IdRegex *regexp.Regexp
}

type RealClock

type RealClock struct{}

func (RealClock) Now

func (t RealClock) Now() time.Time

type ResponseFixture

type ResponseFixture struct {
	Expected map[string]string
	Response *SignableResponseWriter
}

type ResponseSigner

type ResponseSigner interface {
	SignResponse(req *http.Request, rw *SignableResponseWriter, secret string) (string, *AuthenticationError)
	SignResponseDirect(req *http.Request, rw *SignableResponseWriter, secret string) *AuthenticationError
	Check(req *http.Request, resp *http.Response, secret string) *AuthenticationError
	SetTrailer(rw http.ResponseWriter)
}

type SignableResponseWriter

type SignableResponseWriter struct {
	http.ResponseWriter

	Body bytes.Buffer
	// contains filtered or unexported fields
}

func NewDummySignableResponseWriter

func NewDummySignableResponseWriter(body []byte) *SignableResponseWriter

func NewSignableResponseWriter

func NewSignableResponseWriter(h http.ResponseWriter) *SignableResponseWriter

func PrepareResponseWriter

func PrepareResponseWriter(b string) *SignableResponseWriter

func (*SignableResponseWriter) Close

func (s *SignableResponseWriter) Close() (int, error)

func (*SignableResponseWriter) Header

func (s *SignableResponseWriter) Header() http.Header

func (*SignableResponseWriter) Write

func (s *SignableResponseWriter) Write(b []byte) (int, error)

func (*SignableResponseWriter) WriteHeader

func (s *SignableResponseWriter) WriteHeader(status int)

type Signer

type Signer interface {
	// Generates a signature according to a request. Does not alter the request.
	// Fails if headers necessary for signing are missing.
	// Does not alter the contents of the request, but req.Body's address may change.
	Sign(req *http.Request, authHeaders map[string]string, secret string) (string, *AuthenticationError)

	// Returns a regular expression that matches the authorization header for the version of the signature
	// that the signer represents, but not any other version.
	GetIdentificationRegex() *regexp.Regexp

	// Hashes the body of a request according to the signature specifications.
	// Does not alter the contents of the request, but req.Body's address may change.
	HashBody(req *http.Request) (string, *AuthenticationError)

	// Returns a response signer for this type of signature if one exists. May return nil if no specification
	// exists for response signing.
	GetResponseSigner() ResponseSigner

	// Reads the authorization headers from the Authorization field of a request and returns them as a map.
	// Does not alter the request.
	ParseAuthHeaders(req *http.Request) map[string]string

	// Verifies whether or not a request bears a valid Authorization header.
	// May also check other required headers and a return an error if they are missing.
	// In short, Check() verifies whether a signed request is valid, up to specifications and bears the expected signature.
	Check(req *http.Request, secret string) *AuthenticationError

	// Directly signs the request, generating the appropriate headers if necessary.
	SignDirect(req *http.Request, authHeaders map[string]string, secret string) *AuthenticationError

	// Generates the Authorization header's value for a request using the authorization headers and a signature.
	// Does not alter the request.
	// Does not alter the contents of the request, but req.Body's address may change.
	GenerateAuthorization(req *http.Request, authHeaders map[string]string, signature string) (string, *AuthenticationError)

	// Returns a version number, or 0 if unknown.
	Version() int
}

type TestClock

type TestClock struct {
	Timestamp time.Time
}

func NewTestClock

func NewTestClock(timestamp int64) TestClock

func (TestClock) Now

func (t TestClock) Now() time.Time

type TestFixture

type TestFixture struct {
	TestName       string
	Digest         func() hash.Hash
	Expected       map[string]string
	Request        *http.Request
	AuthHeaders    map[string]string
	SecretKey      string
	Response       *ResponseFixture
	SystemTime     int64
	ErrorType      map[string]ErrorType
	ExpectedHeader map[string]string
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL