From 7473735c5311c05ec57d7cd818a1c38e04df47b3 Mon Sep 17 00:00:00 2001 From: Dick Appel Date: Tue, 23 Nov 2021 09:16:39 +0100 Subject: [PATCH] feat: added support for personal-access-tokens - added a new PATAuthTransport type that has a 'Token' attribute to hold your unique PAT - setting the Authorization header with the bearer token in the RoundTrip function. - added test to prove to the token gets passed via the header - bonus: fixed typo in existing test name --- authentication.go | 2 ++ authentication_test.go | 2 +- jira.go | 34 ++++++++++++++++++++++++++++++++++ jira_test.go | 23 +++++++++++++++++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/authentication.go b/authentication.go index bd123b90..c89ae40a 100644 --- a/authentication.go +++ b/authentication.go @@ -13,6 +13,8 @@ const ( authTypeBasic = 1 // HTTP Session Authentication authTypeSession = 2 + // HTTP Personal Access Token Authentication + authTypePAT = 3 ) // AuthenticationService handles authentication for the Jira instance / API. diff --git a/authentication_test.go b/authentication_test.go index 431a7fdc..9235d080 100644 --- a/authentication_test.go +++ b/authentication_test.go @@ -133,7 +133,7 @@ func TestAuthenticationService_Authenticated_WithBasicAuthButNoUsername(t *testi } } -func TestAithenticationService_GetUserInfo_AccessForbidden_Fail(t *testing.T) { +func TestAuthenticationService_GetUserInfo_AccessForbidden_Fail(t *testing.T) { setup() defer teardown() testMux.HandleFunc("/rest/auth/1/session", func(w http.ResponseWriter, r *http.Request) { diff --git a/jira.go b/jira.go index 66046a45..b628ec67 100644 --- a/jira.go +++ b/jira.go @@ -382,6 +382,40 @@ func (t *BasicAuthTransport) transport() http.RoundTripper { return http.DefaultTransport } +// PATAuthTransport is an http.RoundTripper that authenticates all requests +// using the Personal Access Token specified. +type PATAuthTransport struct { + Token string + + // Transport is the underlying HTTP transport to use when making requests. + // It will default to http.DefaultTransport if nil. + Transport http.RoundTripper +} + +// RoundTrip implements the RoundTripper interface. We just add the +// basic auth and return the RoundTripper for this transport type. +func (t *PATAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) { + req2 := cloneRequest(req) // per RoundTripper contract + req2.Header.Set("Authorization", "Bearer "+t.Token) + return t.transport().RoundTrip(req2) +} + +// Client returns an *http.Client that makes requests that are authenticated +// using HTTP Basic Authentication. This is a nice little bit of sugar +// so we can just get the client instead of creating the client in the calling code. +// If it's necessary to send more information on client init, the calling code can +// always skip this and set the transport itself. +func (t *PATAuthTransport) Client() *http.Client { + return &http.Client{Transport: t} +} + +func (t *PATAuthTransport) transport() http.RoundTripper { + if t.Transport != nil { + return t.Transport + } + return http.DefaultTransport +} + // CookieAuthTransport is an http.RoundTripper that authenticates all requests // using Jira's cookie-based authentication. // diff --git a/jira_test.go b/jira_test.go index 9f34dd78..3aedbd64 100644 --- a/jira_test.go +++ b/jira_test.go @@ -631,3 +631,26 @@ func TestJWTAuthTransport_HeaderContainsJWT(t *testing.T) { jwtClient, _ := NewClient(jwtTransport.Client(), testServer.URL) jwtClient.Issue.Get("TEST-1", nil) } + +func TestPATAuthTransport_HeaderContainsAuth(t *testing.T) { + setup() + defer teardown() + + token := "shhh, it's a token" + + patTransport := &PATAuthTransport{ + Token: token, + } + + testMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + val := r.Header.Get("Authorization") + expected := "Bearer " + token + if val != expected { + t.Errorf("request does not contain bearer token in the Authorization header.") + } + }) + + client, _ := NewClient(patTransport.Client(), testServer.URL) + client.User.GetSelf() + +}