/
oauth.go
142 lines (128 loc) · 3.88 KB
/
oauth.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
/*
To the extent possible under law, Konstantin Olkhovskiy has waived
all copyright and related or neighboring rights to this snippet.
CC0 license: http://creativecommons.org/publicdomain/zero/1.0/
*/
package main
import (
"crypto/x509"
"encoding/json"
"encoding/pem"
"fmt"
"log"
"net/http"
"net/url"
"os"
"os/user"
"path/filepath"
"strings"
"github.com/andygrunwald/go-jira"
"github.com/dghubble/oauth1"
"golang.org/x/net/context"
"gopkg.in/alecthomas/kingpin.v2"
)
var (
jiraURL = kingpin.Flag("jira-url", "JIRA instance to use").Default("<your jira here>").URL()
)
/*
$ openssl genrsa -out jira.pem 1024
$ openssl rsa -in jira.pem -pubout -out jira.pub
*/
const jiraPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
<your private key here>
-----END RSA PRIVATE KEY-----`
const jiraConsumerKey = ""
func getJIRAHTTPClient(ctx context.Context, config *oauth1.Config) *http.Client {
cacheFile, err := jiraTokenCacheFile()
if err != nil {
log.Fatalf("Unable to get path to cached credential file. %v", err)
}
tok, err := jiraTokenFromFile(cacheFile)
if err != nil {
tok = getJIRATokenFromWeb(config)
saveJIRAToken(cacheFile, tok)
}
c := config.Client(ctx, tok)
return c
}
func getJIRATokenFromWeb(config *oauth1.Config) *oauth1.Token {
requestToken, requestSecret, err := config.RequestToken()
if err != nil {
log.Fatalf("Unable to get request token. %v", err)
}
authorizationURL, err := config.AuthorizationURL(requestToken)
if err != nil {
log.Fatalf("Unable to get authorization url. %v", err)
}
fmt.Printf("Go to the following link in your browser then type the "+
"authorization code: \n%v\n", authorizationURL.String())
var code string
if _, err := fmt.Scan(&code); err != nil {
log.Fatalf("Unable to read authorization code. %v", err)
}
accessToken, accessSecret, err := config.AccessToken(requestToken, requestSecret, code)
if err != nil {
log.Fatalf("Unable to get access token. %v", err)
}
return oauth1.NewToken(accessToken, accessSecret)
}
func jiraTokenCacheFile() (string, error) {
usr, err := user.Current()
if err != nil {
return "", err
}
tokenCacheDir := filepath.Join(usr.HomeDir, ".credentials")
os.MkdirAll(tokenCacheDir, 0700)
return filepath.Join(tokenCacheDir,
url.QueryEscape((*jiraURL).Host+".json")), err
}
func jiraTokenFromFile(file string) (*oauth1.Token, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
t := &oauth1.Token{}
err = json.NewDecoder(f).Decode(t)
defer f.Close()
return t, err
}
func saveJIRAToken(file string, token *oauth1.Token) {
fmt.Printf("Saving credential file to: %s\n", file)
f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
log.Fatalf("Unable to cache oauth token: %v", err)
}
defer f.Close()
json.NewEncoder(f).Encode(token)
}
func getJIRAClient() *jira.Client {
ctx := context.Background()
keyDERBlock, _ := pem.Decode([]byte(jiraPrivateKey))
if keyDERBlock == nil {
log.Fatal("unable to decode key PEM block")
}
if !(keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY")) {
log.Fatalf("unexpected key DER block type: %s", keyDERBlock.Type)
}
privateKey, err := x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes)
if err != nil {
log.Fatalf("unable to parse PKCS1 private key. %v", err)
}
config := oauth1.Config{
ConsumerKey: jiraConsumerKey,
CallbackURL: "oob", /* for command line usage */
Endpoint: oauth1.Endpoint{
RequestTokenURL: (*jiraURL).String() + "plugins/servlet/oauth/request-token",
AuthorizeURL: (*jiraURL).String() + "plugins/servlet/oauth/authorize",
AccessTokenURL: (*jiraURL).String() + "plugins/servlet/oauth/access-token",
},
Signer: &oauth1.RSASigner{
PrivateKey: privateKey,
},
}
jiraClient, err := jira.NewClient(getJIRAHTTPClient(ctx, &config), (*jiraURL).String())
if err != nil {
log.Fatalf("unable to create new JIRA client. %v", err)
}
return jiraClient
}