forked from andygrunwald/go-jira
-
Notifications
You must be signed in to change notification settings - Fork 0
/
authentication.go
208 lines (176 loc) · 6.26 KB
/
authentication.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
package jira
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
const (
// HTTP Basic Authentication
authTypeBasic = 1
// HTTP Session Authentication
authTypeSession = 2
)
// AuthenticationService handles authentication for the Jira instance / API.
//
// Jira API docs: https://docs.atlassian.com/jira/REST/latest/#authentication
type AuthenticationService struct {
client *Client
// Authentication type
authType int
// Basic auth username
username string
// Basic auth password
password string
}
// Session represents a Session JSON response by the Jira API.
type Session struct {
Self string `json:"self,omitempty"`
Name string `json:"name,omitempty"`
Session struct {
Name string `json:"name"`
Value string `json:"value"`
} `json:"session,omitempty"`
LoginInfo struct {
FailedLoginCount int `json:"failedLoginCount"`
LoginCount int `json:"loginCount"`
LastFailedLoginTime string `json:"lastFailedLoginTime"`
PreviousLoginTime string `json:"previousLoginTime"`
} `json:"loginInfo"`
Cookies []*http.Cookie
}
// AcquireSessionCookieWithContext creates a new session for a user in Jira.
// Once a session has been successfully created it can be used to access any of Jira's remote APIs and also the web UI by passing the appropriate HTTP Cookie header.
// The header will by automatically applied to every API request.
// 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
//
// Deprecated: Use CookieAuthTransport instead
func (s *AuthenticationService) AcquireSessionCookieWithContext(ctx context.Context, username, password string) (bool, error) {
apiEndpoint := "rest/auth/1/session"
body := struct {
Username string `json:"username"`
Password string `json:"password"`
}{
username,
password,
}
req, err := s.client.NewRequestWithContext(ctx, "POST", apiEndpoint, body)
if err != nil {
return false, err
}
session := new(Session)
resp, err := s.client.Do(req, session)
if resp != nil {
session.Cookies = resp.Cookies()
}
if err != nil {
return false, fmt.Errorf("auth at Jira instance failed (HTTP(S) request). %s", err)
}
if resp != nil && resp.StatusCode != 200 {
return false, fmt.Errorf("auth at Jira instance failed (HTTP(S) request). Status code: %d", resp.StatusCode)
}
s.client.session = session
s.authType = authTypeSession
return true, nil
}
// AcquireSessionCookie wraps AcquireSessionCookieWithContext using the background context.
//
// Deprecated: Use CookieAuthTransport instead
func (s *AuthenticationService) AcquireSessionCookie(username, password string) (bool, error) {
return s.AcquireSessionCookieWithContext(context.Background(), username, password)
}
// SetBasicAuth sets username and password for the basic auth against the Jira instance.
//
// Deprecated: Use BasicAuthTransport instead
func (s *AuthenticationService) SetBasicAuth(username, password string) {
s.username = username
s.password = password
s.authType = authTypeBasic
}
// Authenticated reports if the current Client has authentication details for Jira
func (s *AuthenticationService) Authenticated() bool {
if s != nil {
if s.authType == authTypeSession {
return s.client.session != nil
} else if s.authType == authTypeBasic {
return s.username != ""
}
}
return false
}
// LogoutWithContext logs out the current user that has been authenticated and the session in the client is destroyed.
//
// Jira API docs: https://docs.atlassian.com/jira/REST/latest/#auth/1/session
//
// Deprecated: Use CookieAuthTransport to create base client. Logging out is as simple as not using the
// client anymore
func (s *AuthenticationService) LogoutWithContext(ctx context.Context) error {
if s.authType != authTypeSession || s.client.session == nil {
return fmt.Errorf("no user is authenticated")
}
apiEndpoint := "rest/auth/1/session"
req, err := s.client.NewRequestWithContext(ctx, "DELETE", apiEndpoint, nil)
if err != nil {
return fmt.Errorf("creating the request to log the user out failed : %s", err)
}
resp, err := s.client.Do(req, nil)
if err != nil {
return fmt.Errorf("error sending the logout request: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != 204 {
return fmt.Errorf("the logout was unsuccessful with status %d", resp.StatusCode)
}
// If logout successful, delete session
s.client.session = nil
return nil
}
// Logout wraps LogoutWithContext using the background context.
//
// Deprecated: Use CookieAuthTransport to create base client. Logging out is as simple as not using the
// client anymore
func (s *AuthenticationService) Logout() error {
return s.LogoutWithContext(context.Background())
}
// GetCurrentUserWithContext gets the details of the current user.
//
// Jira API docs: https://docs.atlassian.com/jira/REST/latest/#auth/1/session
func (s *AuthenticationService) GetCurrentUserWithContext(ctx context.Context) (*Session, error) {
if s == nil {
return nil, fmt.Errorf("authentication Service is not instantiated")
}
if s.authType != authTypeSession || s.client.session == nil {
return nil, fmt.Errorf("no user is authenticated yet")
}
apiEndpoint := "rest/auth/1/session"
req, err := s.client.NewRequestWithContext(ctx, "GET", apiEndpoint, nil)
if err != nil {
return nil, fmt.Errorf("could not create request for getting user info : %s", err)
}
resp, err := s.client.Do(req, nil)
if err != nil {
return nil, fmt.Errorf("error sending request to get user info : %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("getting user info failed with status : %d", resp.StatusCode)
}
ret := new(Session)
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("couldn't read body from the response : %s", err)
}
err = json.Unmarshal(data, &ret)
if err != nil {
return nil, fmt.Errorf("could not unmarshall received user info : %s", err)
}
return ret, nil
}
// GetCurrentUser wraps GetCurrentUserWithContext using the background context.
func (s *AuthenticationService) GetCurrentUser() (*Session, error) {
return s.GetCurrentUserWithContext(context.Background())
}