mirror of
https://github.com/interviewstreet/go-jira.git
synced 2025-11-25 22:12:08 +02:00
Added transport for cookie authentication and updated docs
This commit is contained in:
51
README.md
51
README.md
@@ -108,34 +108,19 @@ func main() {
|
|||||||
|
|
||||||
#### Authenticate with session cookie
|
#### 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
|
```go
|
||||||
package main
|
tp := jira.CookieAuthTransport{
|
||||||
|
Username: "username",
|
||||||
import (
|
Password: "password",
|
||||||
"fmt"
|
BaseURL: "https://my.jira.com",
|
||||||
"github.com/andygrunwald/go-jira"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
jiraClient, err := jira.NewClient(nil, "https://your.jira-instance.com/")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := jiraClient.Authentication.AcquireSessionCookie("username", "password")
|
client, err := jira.NewClient(tp.Client(), tp.BaseURL)
|
||||||
if err != nil || res == false {
|
u, _, err := client.User.Get("admin")
|
||||||
fmt.Printf("Result: %v\n", res)
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
issue, _, err := jiraClient.Issue.Get("SYS-5156", nil)
|
fmt.Printf("\nEmail: %v\nSuccess!\n", u.EmailAddress)
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("%s: %+v\n", issue.Key, issue.Fields.Summary)
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -158,14 +143,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
jiraClient, err := jira.NewClient(nil, "https://your.jira-instance.com/")
|
tp := jira.CookieAuthTransport{
|
||||||
if err != nil {
|
Username: "username",
|
||||||
panic(err)
|
Password: "password",
|
||||||
|
BaseURL: "https://my.jira.com",
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := jiraClient.Authentication.AcquireSessionCookie("username", "password")
|
jiraClient, err := jira.NewClient(tp.Client(), tp.BaseURL)
|
||||||
if err != nil || res == false {
|
if err != nil {
|
||||||
fmt.Printf("Result: %v\n", res)
|
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +196,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
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)
|
req, _ := jiraClient.NewRequest("GET", "/rest/api/2/project", nil)
|
||||||
|
|
||||||
projects := new([]jira.Project)
|
projects := new([]jira.Project)
|
||||||
|
|||||||
127
jira.go
127
jira.go
@@ -8,8 +8,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/google/go-querystring/query"
|
"github.com/google/go-querystring/query"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Client manages communication with the JIRA API.
|
// A Client manages communication with the JIRA API.
|
||||||
@@ -296,8 +298,10 @@ type BasicAuthTransport struct {
|
|||||||
// RoundTrip implements the RoundTripper interface. We just add the
|
// RoundTrip implements the RoundTripper interface. We just add the
|
||||||
// basic auth and return the RoundTripper for this transport type.
|
// basic auth and return the RoundTripper for this transport type.
|
||||||
func (t *BasicAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
func (t *BasicAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
req.SetBasicAuth(t.Username, t.Password)
|
req2 := cloneRequest(req) // per RoundTripper contract
|
||||||
return t.transport().RoundTrip(req)
|
|
||||||
|
req2.SetBasicAuth(t.Username, t.Password)
|
||||||
|
return t.transport().RoundTrip(req2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client returns an *http.Client that makes requests that are authenticated
|
// Client returns an *http.Client that makes requests that are authenticated
|
||||||
@@ -315,3 +319,122 @@ func (t *BasicAuthTransport) transport() http.RoundTripper {
|
|||||||
}
|
}
|
||||||
return http.DefaultTransport
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -475,7 +475,8 @@ func TestBasicAuthTransport(t *testing.T) {
|
|||||||
Username: username,
|
Username: username,
|
||||||
Password: password,
|
Password: password,
|
||||||
}
|
}
|
||||||
basicAuthClient, _ := NewClient(tp.Client(), "/")
|
|
||||||
|
basicAuthClient, _ := NewClient(tp.Client(), testServer.URL)
|
||||||
req, _ := basicAuthClient.NewRequest("GET", ".", nil)
|
req, _ := basicAuthClient.NewRequest("GET", ".", nil)
|
||||||
basicAuthClient.Do(req, nil)
|
basicAuthClient.Do(req, nil)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user