1
0
mirror of https://github.com/interviewstreet/go-jira.git synced 2024-11-24 08:22:42 +02:00

Added transport for cookie authentication and updated docs

This commit is contained in:
Bob Briski 2018-02-24 16:29:17 -08:00
parent 7b414f4c18
commit f9152870f4
3 changed files with 148 additions and 33 deletions

View File

@ -108,34 +108,19 @@ func main() {
#### Authenticate with session cookie
Here is an example with session cookie authentication.
A more thorough, [runnable example](examples/cookieauth/main.go) is provided in the examples directory.
```go
package main
import (
"fmt"
"github.com/andygrunwald/go-jira"
)
func main() {
jiraClient, err := jira.NewClient(nil, "https://your.jira-instance.com/")
if err != nil {
panic(err)
tp := jira.CookieAuthTransport{
Username: "username",
Password: "password",
BaseURL: "https://my.jira.com",
}
res, err := jiraClient.Authentication.AcquireSessionCookie("username", "password")
if err != nil || res == false {
fmt.Printf("Result: %v\n", res)
panic(err)
}
client, err := jira.NewClient(tp.Client(), tp.BaseURL)
u, _, err := client.User.Get("admin")
issue, _, err := jiraClient.Issue.Get("SYS-5156", nil)
if err != nil {
panic(err)
}
fmt.Printf("%s: %+v\n", issue.Key, issue.Fields.Summary)
fmt.Printf("\nEmail: %v\nSuccess!\n", u.EmailAddress)
}
```
@ -158,14 +143,14 @@ import (
)
func main() {
jiraClient, err := jira.NewClient(nil, "https://your.jira-instance.com/")
if err != nil {
panic(err)
tp := jira.CookieAuthTransport{
Username: "username",
Password: "password",
BaseURL: "https://my.jira.com",
}
res, err := jiraClient.Authentication.AcquireSessionCookie("username", "password")
if err != nil || res == false {
fmt.Printf("Result: %v\n", res)
jiraClient, err := jira.NewClient(tp.Client(), tp.BaseURL)
if err != nil {
panic(err)
}
@ -211,7 +196,13 @@ import (
)
func main() {
jiraClient, _ := jira.NewClient(nil, "https://jira.atlassian.com/")
tp := jira.CookieAuthTransport{
Username: "username",
Password: "password",
BaseURL: "https://my.jira.com",
}
jiraClient, _ := jira.NewClient(tp.Client(), tp.BaseURL)
req, _ := jiraClient.NewRequest("GET", "/rest/api/2/project", nil)
projects := new([]jira.Project)

127
jira.go
View File

@ -8,8 +8,10 @@ import (
"net/http"
"net/url"
"reflect"
"time"
"github.com/google/go-querystring/query"
"github.com/pkg/errors"
)
// A Client manages communication with the JIRA API.
@ -296,8 +298,10 @@ type BasicAuthTransport struct {
// RoundTrip implements the RoundTripper interface. We just add the
// basic auth and return the RoundTripper for this transport type.
func (t *BasicAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
req.SetBasicAuth(t.Username, t.Password)
return t.transport().RoundTrip(req)
req2 := cloneRequest(req) // per RoundTripper contract
req2.SetBasicAuth(t.Username, t.Password)
return t.transport().RoundTrip(req2)
}
// Client returns an *http.Client that makes requests that are authenticated
@ -315,3 +319,122 @@ func (t *BasicAuthTransport) transport() http.RoundTripper {
}
return http.DefaultTransport
}
// CookieAuthTransport is an http.RoundTripper that authenticates all requests
// using Jira's cookie-based authentication.
//
// Note that it is generally preferrable to use HTTP BASIC authentication with the REST API.
// However, this resource may be used to mimic the behaviour of JIRA's log-in page (e.g. to display log-in errors to a user).
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#auth/1/session
type CookieAuthTransport struct {
Username string
Password string
BaseURL string
// SessionObject is the authenticated cookie string.s
// It's passed in each call to prove the client is authenticated.
sessionObject []*http.Cookie
// Transport is the underlying HTTP transport to use when making requests.
// It will default to http.DefaultTransport if nil.
Transport http.RoundTripper
}
// RoundTrip adds the session object to the request.
func (t *CookieAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
if t.sessionObject == nil {
err := t.setSessionObject()
if err != nil {
return nil, errors.Wrap(err, "cookieauth: no session object has been set")
}
}
req2 := cloneRequest(req) // per RoundTripper contract
for _, cookie := range t.sessionObject {
req2.AddCookie(cookie)
}
return t.transport().RoundTrip(req2)
}
// Client returns an *http.Client that makes requests that are authenticated
// using cookie authentication
func (t *CookieAuthTransport) Client() *http.Client {
return &http.Client{Transport: t}
}
// setSessionObject attempts to authenticate the user and set
// the session object (e.g. cookie)
func (t *CookieAuthTransport) setSessionObject() error {
req, err := t.getAuthRequest()
if err != nil {
return err
}
var authClient = &http.Client{
Timeout: time.Second * 60,
}
resp, err := authClient.Do(req)
if err != nil {
return err
}
t.sessionObject = resp.Cookies()
return nil
}
// getAuthRequest assembles the request to get the authenticated cookie
func (t *CookieAuthTransport) getAuthRequest() (*http.Request, error) {
apiEndpoint := "rest/auth/1/session"
body := struct {
Username string `json:"username"`
Password string `json:"password"`
}{
t.Username,
t.Password,
}
ep, err := url.Parse(apiEndpoint)
if err != nil {
return nil, err
}
base, err := url.Parse(t.BaseURL)
if err != nil {
return nil, err
}
u := base.ResolveReference(ep)
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(body)
req, err := http.NewRequest("POST", u.String(), b)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
return req, nil
}
func (t *CookieAuthTransport) transport() http.RoundTripper {
if t.Transport != nil {
return t.Transport
}
return http.DefaultTransport
}
// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
// shallow copy of the struct
r2 := new(http.Request)
*r2 = *r
// deep copy of the Header
r2.Header = make(http.Header, len(r.Header))
for k, s := range r.Header {
r2.Header[k] = append([]string(nil), s...)
}
return r2
}

View File

@ -475,7 +475,8 @@ func TestBasicAuthTransport(t *testing.T) {
Username: username,
Password: password,
}
basicAuthClient, _ := NewClient(tp.Client(), "/")
basicAuthClient, _ := NewClient(tp.Client(), testServer.URL)
req, _ := basicAuthClient.NewRequest("GET", ".", nil)
basicAuthClient.Do(req, nil)
}