Skip to content

Commit

Permalink
Export bulkfhir.{BearerToken,BearerTokenAuthenticator,CredentialExcha…
Browse files Browse the repository at this point in the history
…nger} and processing.TestSink so that they can be used by other libraries

PiperOrigin-RevId: 496925505
  • Loading branch information
Samuel Littley authored and copybara-github committed Dec 21, 2022
1 parent c4f04e2 commit 675b173
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 67 deletions.
68 changes: 34 additions & 34 deletions bulkfhir/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ type Authenticator interface {
AddAuthenticationToRequest(hc *http.Client, req *http.Request) error
}

// bearerToken encapsulates a bearer token presented as an Authorization header.
type bearerToken struct {
// BearerToken encapsulates a bearer token presented as an Authorization header.
type BearerToken struct {
token string
expiry time.Time
alwaysAuthenticateIfNoExpiry bool
Expand All @@ -80,7 +80,7 @@ type bearerToken struct {
// from a previous request, or a default expiry set when the authenticator
// was created.
// - No expiry time is available, and alwaysAuthenticateIfNoExpiry is true.
func (bt *bearerToken) shouldRenew() bool {
func (bt *BearerToken) shouldRenew() bool {
if bt == nil || bt.token == "" {
return true
}
Expand All @@ -94,32 +94,32 @@ func (bt *bearerToken) shouldRenew() bool {
return false
}

func (bt *bearerToken) addHeader(req *http.Request) {
func (bt *BearerToken) addHeader(req *http.Request) {
req.Header.Set(authorizationHeader, fmt.Sprintf("Bearer %s", bt.token))
}

// credentialExchanger is used by bearerTokenAuthenticator to exchange
// CredentialExchanger is used by bearerTokenAuthenticator to exchange
// long-lived credentials for a short lived bearer token.
type credentialExchanger interface {
authenticate(hc *http.Client) (*bearerToken, error)
type CredentialExchanger interface {
Authenticate(hc *http.Client) (*BearerToken, error)
}

// bearerTokenAuthenticator is an implementation of Authenticator which uses a
// credentialExchanger to obtain a bearer token which is presented in an
// BearerTokenAuthenticator is an implementation of Authenticator which uses a
// CredentialExchanger to obtain a bearer token which is presented in an
// Authorization header.
//
// Note: this implementation is not thread safe.
type bearerTokenAuthenticator struct {
exchanger credentialExchanger
token *bearerToken
type BearerTokenAuthenticator struct {
Exchanger CredentialExchanger
token *BearerToken
}

// Authenticate is Authenticator.Authenticate.
//
// This Authenticator uses the credentialExchanger it contains to obtain a
// This Authenticator uses the CredentialExchanger it contains to obtain a
// bearer token.
func (bta *bearerTokenAuthenticator) Authenticate(hc *http.Client) error {
token, err := bta.exchanger.authenticate(hc)
func (bta *BearerTokenAuthenticator) Authenticate(hc *http.Client) error {
token, err := bta.Exchanger.Authenticate(hc)
if err != nil {
return err
}
Expand All @@ -129,9 +129,9 @@ func (bta *bearerTokenAuthenticator) Authenticate(hc *http.Client) error {

// AuthenticateIfNecessary is Authenticator.AuthenticateIfNecessary.
//
// This Authenticator uses the credentialExchanger it contains to obtain a
// This Authenticator uses the CredentialExchanger it contains to obtain a
// bearer token.
func (bta *bearerTokenAuthenticator) AuthenticateIfNecessary(hc *http.Client) error {
func (bta *BearerTokenAuthenticator) AuthenticateIfNecessary(hc *http.Client) error {
if bta.token.shouldRenew() {
return bta.Authenticate(hc)
}
Expand All @@ -142,7 +142,7 @@ func (bta *bearerTokenAuthenticator) AuthenticateIfNecessary(hc *http.Client) er
//
// This Authenticator adds an access token as an Authorization: Bearer {token}
// header, automatically requesting/refreshing the token as necessary.
func (bta *bearerTokenAuthenticator) AddAuthenticationToRequest(hc *http.Client, req *http.Request) error {
func (bta *BearerTokenAuthenticator) AddAuthenticationToRequest(hc *http.Client, req *http.Request) error {
if err := bta.AuthenticateIfNecessary(hc); err != nil {
return err
}
Expand Down Expand Up @@ -201,8 +201,8 @@ func (tr *tokenResponse) UnmarshalJSON(data []byte) error {
return nil
}

func (tr *tokenResponse) toBearerToken(defaultExpiry time.Duration, alwaysAuthenticateIfNoExpiry bool) *bearerToken {
bt := &bearerToken{
func (tr *tokenResponse) toBearerToken(defaultExpiry time.Duration, alwaysAuthenticateIfNoExpiry bool) *BearerToken {
bt := &BearerToken{
token: tr.Token,
alwaysAuthenticateIfNoExpiry: alwaysAuthenticateIfNoExpiry,
}
Expand All @@ -214,9 +214,9 @@ func (tr *tokenResponse) toBearerToken(defaultExpiry time.Duration, alwaysAuthen
return bt
}

// doOAuthExchange sends a HTTP request which is expected to return a JSON
// response matching tokenResponse.
func doOAuthExchange(hc *http.Client, req *http.Request, defaultExpiry time.Duration, alwaysAuthenticateIfNoExpiresIn bool) (*bearerToken, error) {
// DoOAuthExchange sends a HTTP request which is expected to return a JSON
// response with "token" and "expires_in" fields.
func DoOAuthExchange(hc *http.Client, req *http.Request, defaultExpiry time.Duration, alwaysAuthenticateIfNoExpiresIn bool) (*BearerToken, error) {
resp, err := hc.Do(req)
if err != nil {
return nil, err
Expand All @@ -239,7 +239,7 @@ func doOAuthExchange(hc *http.Client, req *http.Request, defaultExpiry time.Dura
return tr.toBearerToken(defaultExpiry, alwaysAuthenticateIfNoExpiresIn), nil
}

// httpBasicOAuthExchanger is an implementation of credentialExchanger for use
// httpBasicOAuthExchanger is an implementation of CredentialExchanger for use
// with bearerTokenAuthenticator which performs a 2-legged OAuth2 handshake
// using HTTP Basic Authentication to obtain an access token, which is presented
// as an "Authorization: Bearer {token}" header in all requests.
Expand Down Expand Up @@ -267,11 +267,11 @@ func (hboe *httpBasicOAuthExchanger) buildBody() io.Reader {
return bytes.NewBufferString(v.Encode())
}

// authenticate is credentialExchanger.authenticate.
// Authenticate is CredentialExchanger.Authenticate.
//
// This credentialExchanger performs 2-legged OAuth using HTTP Basic
// This CredentialExchanger performs 2-legged OAuth using HTTP Basic
// Authentication to obtain an expiry token.
func (hboe *httpBasicOAuthExchanger) authenticate(hc *http.Client) (*bearerToken, error) {
func (hboe *httpBasicOAuthExchanger) Authenticate(hc *http.Client) (*BearerToken, error) {
req, err := http.NewRequest(http.MethodPost, hboe.tokenURL, hboe.buildBody())
if err != nil {
return nil, err
Expand All @@ -281,7 +281,7 @@ func (hboe *httpBasicOAuthExchanger) authenticate(hc *http.Client) (*bearerToken
req.Header.Add(acceptHeader, acceptHeaderJSON)
req.Header.Add(contentTypeHeader, contentTypeFormURLEncoded)

return doOAuthExchange(hc, req, hboe.defaultExpiry, hboe.alwaysAuthenticateIfNoExpiresIn)
return DoOAuthExchange(hc, req, hboe.defaultExpiry, hboe.alwaysAuthenticateIfNoExpiresIn)
}

// HTTPBasicOAuthOptions contains optional parameters used by
Expand Down Expand Up @@ -332,7 +332,7 @@ func NewHTTPBasicOAuthAuthenticator(username, password, tokenURL string, opts *H
e.defaultExpiry = opts.DefaultExpiry
}

return &bearerTokenAuthenticator{exchanger: e}, nil
return &BearerTokenAuthenticator{Exchanger: e}, nil
}

// A JWTKeyProvider provides the RSA private key used for signing JSON Web Tokens.
Expand Down Expand Up @@ -420,11 +420,11 @@ func (joe *jwtOAuthExchanger) buildBody() (io.Reader, error) {
return bytes.NewBufferString(v.Encode()), nil
}

// authenticate is credentialExchanger.authenticate.
// Authenticate is CredentialExchanger.Authenticate.
//
// This credentialExchanger performs 2-legged OAuth using HTTP Basic
// This CredentialExchanger performs 2-legged OAuth using HTTP Basic
// Authentication to obtain an expiry token.
func (joe *jwtOAuthExchanger) authenticate(hc *http.Client) (*bearerToken, error) {
func (joe *jwtOAuthExchanger) Authenticate(hc *http.Client) (*BearerToken, error) {
body, err := joe.buildBody()
if err != nil {
return nil, err
Expand All @@ -437,7 +437,7 @@ func (joe *jwtOAuthExchanger) authenticate(hc *http.Client) (*bearerToken, error
req.Header.Add(acceptHeader, acceptHeaderJSON)
req.Header.Add(contentTypeHeader, contentTypeFormURLEncoded)

return doOAuthExchange(hc, req, joe.defaultExpiry, joe.alwaysAuthenticateIfNoExpiresIn)
return DoOAuthExchange(hc, req, joe.defaultExpiry, joe.alwaysAuthenticateIfNoExpiresIn)
}

// JWTOAuthOptions contains optional parameters used by NewJWTOAuthAuthenticator.
Expand Down Expand Up @@ -494,5 +494,5 @@ func NewJWTOAuthAuthenticator(issuer, subject, tokenURL string, keyProvider JWTK
}
}

return &bearerTokenAuthenticator{exchanger: e}, nil
return &BearerTokenAuthenticator{Exchanger: e}, nil
}
2 changes: 1 addition & 1 deletion bulkfhir/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ func TestClient_MonitorJobStatus(t *testing.T) {
if err != nil {
t.Fatal(err)
}
auth.(*bearerTokenAuthenticator).token = &bearerToken{
auth.(*BearerTokenAuthenticator).token = &BearerToken{
token: "123",
expiry: time.Now().Add(5 * time.Minute),
}
Expand Down
4 changes: 2 additions & 2 deletions fhir/processing/bcdarectify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,15 @@ func TestBcdaRectifyProcessor(t *testing.T) {

for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
ts := &testSink{}
ts := &processing.TestSink{}
p, err := processing.NewPipeline([]processing.Processor{processing.NewBCDARectifyProcessor()}, []processing.Sink{ts})
if err != nil {
t.Fatalf("NewPipeline() returned unexpected error: %v", err)
}
if err := p.Process(context.Background(), tc.resourceType, "", tc.jsonIn); err != nil {
t.Fatalf("pipeline.Process(..., %s) returned unexpected error: %v", tc.jsonIn, err)
}
gotJSON, err := ts.writtenResources[0].JSON()
gotJSON, err := ts.WrittenResources[0].JSON()
if err != nil {
t.Fatalf("writtenResource.JSON() returned unexpected error: %v", err)
}
Expand Down
6 changes: 3 additions & 3 deletions fhir/processing/documents_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func TestDocumentsProcessor(t *testing.T) {
t.Fatal(err)
}
defer os.RemoveAll(tempdir)
ts := &testSink{}
ts := &processing.TestSink{}
authenticator, err := bulkfhir.NewHTTPBasicOAuthAuthenticator("username", "password", server.URL+"/auth", nil)
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -121,7 +121,7 @@ func TestDocumentsProcessor(t *testing.T) {
// that the filename in the output resource exists, and then populate the
// wanted resource with the filename that was written.

gotResource, err := ts.writtenResources[0].Proto()
gotResource, err := ts.WrittenResources[0].Proto()
if err != nil {
t.Fatalf("writtenResource.Proto() returned unexpected error: %v", err)
}
Expand All @@ -139,7 +139,7 @@ func TestDocumentsProcessor(t *testing.T) {
tc.wantJSON = strings.Replace(tc.wantJSON, fmt.Sprintf("FILEPATH%d", i), strings.ReplaceAll(url, `\`, `\\`), 1)
}

gotJSON, err := ts.writtenResources[0].JSON()
gotJSON, err := ts.WrittenResources[0].JSON()
if err != nil {
t.Fatalf("writtenResource.JSON() returned unexpected error: %v", err)
}
Expand Down
28 changes: 14 additions & 14 deletions fhir/processing/processing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ func (tp *testProcessor) Process(ctx context.Context, resource processing.Resour
}

func TestTeeFHIRSink(t *testing.T) {
ts1 := &testSink{}
ts2 := &testSink{}
ts1 := &processing.TestSink{}
ts2 := &processing.TestSink{}
ctx := context.Background()
p, err := processing.NewPipeline([]processing.Processor{&testProcessor{}}, []processing.Sink{ts1, ts2})
if err != nil {
Expand All @@ -50,24 +50,24 @@ func TestTeeFHIRSink(t *testing.T) {
if err := p.Finalize(ctx); err != nil {
t.Fatalf("p.Finalize() returned unexpected error: %v", err)
}
for i, ts := range []*testSink{ts1, ts2} {
if len(ts.writtenResources) != 1 {
t.Fatalf("testSink %d captured %d resources, want 1", i, len(ts.writtenResources))
for i, ts := range []*processing.TestSink{ts1, ts2} {
if len(ts.WrittenResources) != 1 {
t.Fatalf("TestSink %d captured %d resources, want 1", i, len(ts.WrittenResources))
}
if ts.writtenResources[0].Type() != resourceType {
t.Errorf("testSink %d captured unexpected resource type: got %s, want %s", i, ts.writtenResources[0].Type(), resourceType)
if ts.WrittenResources[0].Type() != resourceType {
t.Errorf("TestSink %d captured unexpected resource type: got %s, want %s", i, ts.WrittenResources[0].Type(), resourceType)
}
if ts.writtenResources[0].SourceURL() != sourceURL {
t.Errorf("testSink %d captured unexpected resource type: got %q, want %q", i, ts.writtenResources[0].SourceURL(), sourceURL)
if ts.WrittenResources[0].SourceURL() != sourceURL {
t.Errorf("TestSink %d captured unexpected resource type: got %q, want %q", i, ts.WrittenResources[0].SourceURL(), sourceURL)
}
json, err := ts.writtenResources[0].JSON()
json, err := ts.WrittenResources[0].JSON()
if err != nil {
t.Errorf("testSink %d JSON() returned unexpected error: %v", i, err)
t.Errorf("TestSink %d JSON() returned unexpected error: %v", i, err)
} else if !cmp.Equal(json, data) {
t.Errorf("testSink %d captured unexpected data: got %s, want %s", i, json, data)
t.Errorf("TestSink %d captured unexpected data: got %s, want %s", i, json, data)
}
if !ts.finalizeCalled {
t.Errorf("Finalize not called on testSink %d", i)
if !ts.FinalizeCalled {
t.Errorf("Finalize not called on TestSink %d", i)
}
}
}
26 changes: 13 additions & 13 deletions fhir/processing/testsink_test.go → fhir/processing/testsink.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,29 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package processing_test
package processing

import (
"context"

"github.com/google/medical_claims_tools/fhir/processing"
)

// testSink can be used for testing processors by capturing processed resources.
type testSink struct {
writtenResources []processing.ResourceWrapper
finalizeCalled bool
// TestSink can be used for testing processors by capturing processed resources.
type TestSink struct {
WrittenResources []ResourceWrapper
FinalizeCalled bool
}

func (ts *testSink) Write(ctx context.Context, resource processing.ResourceWrapper) error {
ts.writtenResources = append(ts.writtenResources, resource)
// Write is Sink.Write
func (ts *TestSink) Write(ctx context.Context, resource ResourceWrapper) error {
ts.WrittenResources = append(ts.WrittenResources, resource)
return nil
}

func (ts *testSink) Finalize(ctx context.Context) error {
ts.finalizeCalled = true
// Finalize is Sink.Finalize
func (ts *TestSink) Finalize(ctx context.Context) error {
ts.FinalizeCalled = true
return nil
}

// Assert that testSink satisfies the Sink interface.
var _ processing.Sink = &testSink{}
// Assert that TestSink satisfies the Sink interface.
var _ Sink = &TestSink{}

0 comments on commit 675b173

Please sign in to comment.