From 513c9318fb6890cc25fdd4340f057f35418a41c5 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 10 Aug 2016 11:18:24 +0100 Subject: [PATCH] Allow the creation of [un]authenticated JIRA clients --- .../matrix-org/go-neb/realms/jira/jira.go | 75 ++++++++++++++++++- 1 file changed, 72 insertions(+), 3 deletions(-) diff --git a/src/github.com/matrix-org/go-neb/realms/jira/jira.go b/src/github.com/matrix-org/go-neb/realms/jira/jira.go index 3b83708..15eb440 100644 --- a/src/github.com/matrix-org/go-neb/realms/jira/jira.go +++ b/src/github.com/matrix-org/go-neb/realms/jira/jira.go @@ -6,8 +6,12 @@ import ( "encoding/json" "encoding/pem" "errors" + log "github.com/Sirupsen/logrus" + "github.com/andygrunwald/go-jira" + "github.com/dghubble/oauth1" "github.com/matrix-org/go-neb/realms/jira/urls" "github.com/matrix-org/go-neb/types" + "golang.org/x/net/context" "net/http" ) @@ -49,12 +53,22 @@ func (r *jiraRealm) Register() error { if err != nil { return err } + r.JIRAEndpoint = ju.Base // Check to see if JIRA endpoint is valid by pinging an endpoint - err = jiraClient(ju, "") + cli, err := r.jiraClient(ju, "", true) if err != nil { return err } + info, err := jiraServerInfo(cli) + if err != nil { + return err + } + log.WithFields(log.Fields{ + "jira_url": ju.Base, + "title": info.ServerTitle, + "version": info.Version, + }).Print("Found JIRA endpoint") return nil } @@ -71,6 +85,47 @@ func (r *jiraRealm) AuthSession(id, userID, realmID string) types.AuthSession { return nil } +// jiraClient returns an authenticated jira.Client for the given userID. Returns an unauthenticated +// client if allowUnauth is true and no authenticated session is found, else returns an error. +func (r *jiraRealm) jiraClient(u urls.JIRAURL, userID string, allowUnauth bool) (*jira.Client, error) { + // TODO: Check if user has an auth session. Requires access token+secret + hasAuthSession := false + + if hasAuthSession { + // make an authenticated client + var cli *jira.Client + + auth := &oauth1.Config{ + ConsumerKey: r.ConsumerKey, + ConsumerSecret: r.ConsumerSecret, + CallbackURL: u.Base + "realms/redirect/" + r.id, + // TODO: In JIRA Cloud, the Authorization URL is only the Instance BASE_URL: + // https://BASE_URL.atlassian.net. + // It also does not require the + "/plugins/servlet/oauth/authorize" + // We should probably check the provided JIRA base URL to see if it is a cloud one + // then adjust accordingly. + Endpoint: oauth1.Endpoint{ + RequestTokenURL: u.Base + "plugins/servlet/oauth/request-token", + AuthorizeURL: u.Base + "plugins/servlet/oauth/authorize", + AccessTokenURL: u.Base + "plugins/servlet/oauth/access-token", + }, + Signer: &oauth1.RSASigner{ + PrivateKey: r.privateKey, + }, + } + + httpClient := auth.Client(context.TODO(), oauth1.NewToken("access_tokenTODO", "access_secretTODO")) + cli, err := jira.NewClient(httpClient, u.Base) + return cli, err + } else if allowUnauth { + // make an unauthenticated client + cli, err := jira.NewClient(nil, u.Base) + return cli, err + } else { + return nil, errors.New("No authenticated session found for " + userID) + } +} + func (r *jiraRealm) parsePrivateKey() error { pk, err := loadPrivateKey(r.PrivateKeyPEM) if err != nil { @@ -113,8 +168,22 @@ func publicKeyAsPEM(pkey *rsa.PrivateKey) (string, error) { return string(pem.EncodeToMemory(&block)), nil } -func jiraClient(u urls.JIRAURL, userID string) error { - return nil +// jiraServiceInfo is the HTTP response to JIRA_ENDPOINT/rest/api/2/serverInfo +type jiraServiceInfo struct { + ServerTitle string `json:"serverTitle"` + Version string `json:"version"` + VersionNumbers []int `json:"versionNumbers"` + BaseURL string `json:"baseUrl"` +} + +func jiraServerInfo(cli *jira.Client) (*jiraServiceInfo, error) { + var jsi jiraServiceInfo + req, _ := cli.NewRequest("GET", "rest/api/2/serverInfo", nil) + _, err := cli.Do(req, &jsi) + if err != nil { + return nil, err + } + return &jsi, nil } func init() {