Skip to content

Commit

Permalink
Moved OriginatingIdentityHeader to its own package and added tests.
Browse files Browse the repository at this point in the history
[#161523486]

Signed-off-by: Felisia Martini <[email protected]>
Co-authored-by: Felisia Martini <[email protected]>
  • Loading branch information
Kieron Browne and FelisiaM committed Jan 3, 2019
1 parent 867d4b3 commit 834cef1
Show file tree
Hide file tree
Showing 6 changed files with 997 additions and 24 deletions.
49 changes: 38 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,65 @@
# brokerapi

[![Build Status](https://travis-ci.org/pivotal-cf/brokerapi.svg?branch=master)](https://travis-ci.org/pivotal-cf/brokerapi)
[![Build
Status](https://travis-ci.org/pivotal-cf/brokerapi.svg?branch=master)](https://travis-ci.org/pivotal-cf/brokerapi)

A Go package for building [V2 Open Service Broker API](https://github.com/openservicebrokerapi/servicebroker/) compliant Service Brokers.
A Go package for building [V2 Open Service Broker
API](https://github.com/openservicebrokerapi/servicebroker/) compliant Service
Brokers.

## [Docs](https://godoc.org/github.com/pivotal-cf/brokerapi)

## Dependencies

- Go 1.7+
- [lager](https://github.com/cloudfoundry/lager)
- [gorilla/mux](https://github.com/gorilla/mux)
- [gorilla/mux v1.6.1+](https://github.com/gorilla/mux)

We use [dep](https://github.com/golang/dep) to manager our dependencies. Use `dep ensure` in order to download the required packages.
We use [dep](https://github.com/golang/dep) to manager our dependencies. Use
`dep ensure` in order to download the required packages.

## Usage

`brokerapi` defines a [`ServiceBroker`](https://godoc.org/github.com/pivotal-cf/brokerapi#ServiceBroker) interface. Pass an implementation of this to [`brokerapi.New`](https://godoc.org/github.com/pivotal-cf/brokerapi#New), which returns an `http.Handler` that you can use to serve handle HTTP requests.
`brokerapi` defines a
[`ServiceBroker`](https://godoc.org/github.com/pivotal-cf/brokerapi#ServiceBroker)
interface. Pass an implementation of this to
[`brokerapi.New`](https://godoc.org/github.com/pivotal-cf/brokerapi#New), which
returns an `http.Handler` that you can use to serve handle HTTP requests.

Alternatively, if you already have a `*mux.Router` that you want to attach service broker routes to, you can use [`brokerapi.AttachRoutes`](https://godoc.org/github.com/pivotal-cf/brokerapi#AttachRoutes).
Alternatively, if you already have a `*mux.Router` that you want to attach
service broker routes to, you can use
[`brokerapi.AttachRoutes`](https://godoc.org/github.com/pivotal-cf/brokerapi#AttachRoutes).
Note in this case, the Basic Authentication and Originating Identity middleware
will not be set up, so you will have to attach them manually if required.

## Error types

`brokerapi` defines a handful of error types in `service_broker.go` for some common error cases that your service broker may encounter. Return these from your `ServiceBroker` methods where appropriate, and `brokerapi` will do the "right thing" (™), and give Cloud Foundry an appropriate status code, as per the [Service Broker API specification](https://docs.cloudfoundry.org/services/api.html).
`brokerapi` defines a handful of error types in `service_broker.go` for some
common error cases that your service broker may encounter. Return these from
your `ServiceBroker` methods where appropriate, and `brokerapi` will do the
"right thing" (™), and give Cloud Foundry an appropriate status code, as per
the [Service Broker API
specification](https://docs.cloudfoundry.org/services/api.html).

### Custom Errors

`NewFailureResponse()` allows you to return a custom error from any of the `ServiceBroker` interface methods which return an error. Within this you must define an error, a HTTP response status code and a logging key. You can also use the `NewFailureResponseBuilder()` to add a custom `Error:` value in the response, or indicate that the broker should return an empty response rather than the error message.
`NewFailureResponse()` allows you to return a custom error from any of the
`ServiceBroker` interface methods which return an error. Within this you must
define an error, a HTTP response status code and a logging key. You can also
use the `NewFailureResponseBuilder()` to add a custom `Error:` value in the
response, or indicate that the broker should return an empty response rather
than the error message.

## Originating Identity

The request context for every request contains the unparsed `X-Broker-API-Originating-Identity` header under the key `originatingIdentityKey`.
More details on how the Open Service Broker API manages request originating identity is available [here](https://github.com/openservicebrokerapi/servicebroker/blob/master/spec.md#originating-identity).
The request context for every request contains the unparsed
`X-Broker-API-Originating-Identity` header under the key
`originatingIdentityKey`. More details on how the Open Service Broker API
manages request originating identity is available
[here](https://github.com/openservicebrokerapi/servicebroker/blob/master/spec.md#originating-identity).

## Example Service Broker

You can see the [cf-redis](https://github.com/pivotal-cf/cf-redis-broker/blob/2f0e9a8ebb1012a9be74bbef2d411b0b3b60352f/broker/broker.go) service broker uses the BrokerAPI package to create a service broker for Redis.
You can see the
[cf-redis](https://github.com/pivotal-cf/cf-redis-broker/blob/2f0e9a8ebb1012a9be74bbef2d411b0b3b60352f/broker/broker.go)
service broker uses the BrokerAPI package to create a service broker for Redis.
18 changes: 5 additions & 13 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
package brokerapi

import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/pivotal-cf/brokerapi/middlewares/originating_identity_header"
"net/http"
"strconv"

Expand All @@ -40,8 +40,6 @@ const (
lastBindingOperationLogKey = "lastBindingOperation"
catalogLogKey = "catalog"

originatingIdentityKey = "originatingIdentity"

instanceIDLogKey = "instance-id"
instanceDetailsLogKey = "instance-details"
bindingIDLogKey = "binding-id"
Expand Down Expand Up @@ -85,7 +83,9 @@ func New(serviceBroker ServiceBroker, logger lager.Logger, brokerCredentials Bro
AttachRoutes(router, serviceBroker, logger)

authMiddleware := auth.NewWrapper(brokerCredentials.Username, brokerCredentials.Password).Wrap
router.Use(authMiddleware, brokerApiOriginatingIdentityMiddleware)
router.Use(authMiddleware)
router.Use(originating_identity_header.AddToContext)

return router
}

Expand Down Expand Up @@ -797,12 +797,4 @@ func checkBrokerAPIVersionHdr(req *http.Request) (brokerVersion, error) {
return version, errors.New("X-Broker-API-Version Header must be 2.x")
}
return version, nil
}

func brokerApiOriginatingIdentityMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
originatingIdentity := req.Header.Get("X-Broker-API-Originating-Identity")
newCtx := context.WithValue(req.Context(), originatingIdentityKey, originatingIdentity)
next.ServeHTTP(w, req.WithContext(newCtx))
})
}
}
50 changes: 50 additions & 0 deletions api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,56 @@ var _ = Describe("Service Broker API", func() {
})
})

Describe("OriginatingIdentityHeader", func(){

var (
fakeServiceBroker *fakes.AutoFakeServiceBroker
req *http.Request
testServer *httptest.Server
)

BeforeEach(func() {
fakeServiceBroker = new(fakes.AutoFakeServiceBroker)
brokerAPI = brokerapi.New(fakeServiceBroker, brokerLogger, credentials)

testServer = httptest.NewServer(brokerAPI)
var err error
req, err = http.NewRequest("GET", testServer.URL+"/v2/catalog", nil)
Expect(err).NotTo(HaveOccurred())
req.Header.Add("X-Broker-API-Version", "2.14")
req.SetBasicAuth(credentials.Username, credentials.Password)
})

AfterEach(func() {
testServer.Close()
})

When("X-Broker-API-Originating-Identity is passed", func(){
It("Adds it to the context", func(){
originatingIdentity := "Originating Identity Name"
req.Header.Add("X-Broker-API-Originating-Identity", originatingIdentity)

_, err := http.DefaultClient.Do(req)
Expect(err).NotTo(HaveOccurred())

Expect(fakeServiceBroker.ServicesCallCount()).To(Equal(1), "Services was not called")
ctx := fakeServiceBroker.ServicesArgsForCall(0)
Expect(ctx.Value("originatingIdentity")).To(Equal(originatingIdentity))

})
})
When("X-Broker-API-Originating-Identity is not passed", func(){
It("Adds empty originatingIdentity to the context", func(){
_, err := http.DefaultClient.Do(req)
Expect(err).NotTo(HaveOccurred())

Expect(fakeServiceBroker.ServicesCallCount()).To(Equal(1), "Services was not called")
ctx := fakeServiceBroker.ServicesArgsForCall(0)
Expect(ctx.Value("originatingIdentity")).To(Equal(""))
})
})
})

Describe("catalog endpoint", func() {
makeCatalogRequest := func(apiVersion string, fail bool) *httptest.ResponseRecorder {
recorder := httptest.NewRecorder()
Expand Down
Loading

0 comments on commit 834cef1

Please sign in to comment.