2018-06-02 00:37:01 +00:00
package jira
import (
2021-10-06 17:33:14 +00:00
"context"
2018-06-02 00:37:01 +00:00
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
const (
// HTTP Basic Authentication
authTypeBasic = 1
// HTTP Session Authentication
authTypeSession = 2
)
2021-10-06 17:33:14 +00:00
// AuthenticationService handles authentication for the Jira instance / API.
2018-06-02 00:37:01 +00:00
//
2021-10-06 17:33:14 +00:00
// Jira API docs: https://docs.atlassian.com/jira/REST/latest/#authentication
2018-06-02 00:37:01 +00:00
type AuthenticationService struct {
client * Client
// Authentication type
authType int
// Basic auth username
username string
// Basic auth password
password string
}
2021-10-06 17:33:14 +00:00
// Session represents a Session JSON response by the Jira API.
2018-06-02 00:37:01 +00:00
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
}
2021-10-06 17:33:14 +00:00
// 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.
2018-06-02 00:37:01 +00:00
// 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.
2021-10-06 17:33:14 +00:00
// 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).
2018-06-02 00:37:01 +00:00
//
2021-10-06 17:33:14 +00:00
// Jira API docs: https://docs.atlassian.com/jira/REST/latest/#auth/1/session
2018-06-02 00:37:01 +00:00
//
// Deprecated: Use CookieAuthTransport instead
2021-10-06 17:33:14 +00:00
func ( s * AuthenticationService ) AcquireSessionCookieWithContext ( ctx context . Context , username , password string ) ( bool , error ) {
2018-06-02 00:37:01 +00:00
apiEndpoint := "rest/auth/1/session"
body := struct {
Username string ` json:"username" `
Password string ` json:"password" `
} {
username ,
password ,
}
2021-10-06 17:33:14 +00:00
req , err := s . client . NewRequestWithContext ( ctx , "POST" , apiEndpoint , body )
2018-06-02 00:37:01 +00:00
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 {
2021-10-06 17:33:14 +00:00
return false , fmt . Errorf ( "auth at Jira instance failed (HTTP(S) request). %s" , err )
2018-06-02 00:37:01 +00:00
}
if resp != nil && resp . StatusCode != 200 {
2021-10-06 17:33:14 +00:00
return false , fmt . Errorf ( "auth at Jira instance failed (HTTP(S) request). Status code: %d" , resp . StatusCode )
2018-06-02 00:37:01 +00:00
}
s . client . session = session
s . authType = authTypeSession
return true , nil
}
2021-10-06 17:33:14 +00:00
// 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.
2018-06-02 00:37:01 +00:00
//
// Deprecated: Use BasicAuthTransport instead
func ( s * AuthenticationService ) SetBasicAuth ( username , password string ) {
s . username = username
s . password = password
s . authType = authTypeBasic
}
2021-10-06 17:33:14 +00:00
// Authenticated reports if the current Client has authentication details for Jira
2018-06-02 00:37:01 +00:00
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
}
2021-10-06 17:33:14 +00:00
// LogoutWithContext logs out the current user that has been authenticated and the session in the client is destroyed.
2018-06-02 00:37:01 +00:00
//
2021-10-06 17:33:14 +00:00
// Jira API docs: https://docs.atlassian.com/jira/REST/latest/#auth/1/session
2018-06-02 00:37:01 +00:00
//
// Deprecated: Use CookieAuthTransport to create base client. Logging out is as simple as not using the
// client anymore
2021-10-06 17:33:14 +00:00
func ( s * AuthenticationService ) LogoutWithContext ( ctx context . Context ) error {
2018-06-02 00:37:01 +00:00
if s . authType != authTypeSession || s . client . session == nil {
return fmt . Errorf ( "no user is authenticated" )
}
apiEndpoint := "rest/auth/1/session"
2021-10-06 17:33:14 +00:00
req , err := s . client . NewRequestWithContext ( ctx , "DELETE" , apiEndpoint , nil )
2018-06-02 00:37:01 +00:00
if err != nil {
2021-10-06 17:33:14 +00:00
return fmt . Errorf ( "creating the request to log the user out failed : %s" , err )
2018-06-02 00:37:01 +00:00
}
resp , err := s . client . Do ( req , nil )
if err != nil {
2021-10-06 17:33:14 +00:00
return fmt . Errorf ( "error sending the logout request: %s" , err )
2018-06-02 00:37:01 +00:00
}
if resp . StatusCode != 204 {
2021-10-06 17:33:14 +00:00
return fmt . Errorf ( "the logout was unsuccessful with status %d" , resp . StatusCode )
2018-06-02 00:37:01 +00:00
}
// If logout successful, delete session
s . client . session = nil
return nil
}
2021-10-06 17:33:14 +00:00
// Logout wraps LogoutWithContext using the background context.
2018-06-02 00:37:01 +00:00
//
2021-10-06 17:33:14 +00:00
// 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 ) {
2018-06-02 00:37:01 +00:00
if s == nil {
2021-10-06 17:33:14 +00:00
return nil , fmt . Errorf ( "authentication Service is not instantiated" )
2018-06-02 00:37:01 +00:00
}
if s . authType != authTypeSession || s . client . session == nil {
2021-10-06 17:33:14 +00:00
return nil , fmt . Errorf ( "no user is authenticated yet" )
2018-06-02 00:37:01 +00:00
}
apiEndpoint := "rest/auth/1/session"
2021-10-06 17:33:14 +00:00
req , err := s . client . NewRequestWithContext ( ctx , "GET" , apiEndpoint , nil )
2018-06-02 00:37:01 +00:00
if err != nil {
2021-10-06 17:33:14 +00:00
return nil , fmt . Errorf ( "could not create request for getting user info : %s" , err )
2018-06-02 00:37:01 +00:00
}
resp , err := s . client . Do ( req , nil )
if err != nil {
2021-10-06 17:33:14 +00:00
return nil , fmt . Errorf ( "error sending request to get user info : %s" , err )
2018-06-02 00:37:01 +00:00
}
if resp . StatusCode != 200 {
2021-10-06 17:33:14 +00:00
return nil , fmt . Errorf ( "getting user info failed with status : %d" , resp . StatusCode )
2018-06-02 00:37:01 +00:00
}
defer resp . Body . Close ( )
ret := new ( Session )
data , err := ioutil . ReadAll ( resp . Body )
if err != nil {
2021-10-06 17:33:14 +00:00
return nil , fmt . Errorf ( "couldn't read body from the response : %s" , err )
2018-06-02 00:37:01 +00:00
}
err = json . Unmarshal ( data , & ret )
if err != nil {
2021-10-06 17:33:14 +00:00
return nil , fmt . Errorf ( "could not unmarshall received user info : %s" , err )
2018-06-02 00:37:01 +00:00
}
return ret , nil
}
2021-10-06 17:33:14 +00:00
// GetCurrentUser wraps GetCurrentUserWithContext using the background context.
func ( s * AuthenticationService ) GetCurrentUser ( ) ( * Session , error ) {
return s . GetCurrentUserWithContext ( context . Background ( ) )
}