From 0948f59a1a738eed6d0ad37e256201b18d9cd75a Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 9 Aug 2016 17:27:23 +0100 Subject: [PATCH 1/3] Add JiraRealm type. Add Register() function to AuthRealms Verify that PrivateKeyPEM is indeed a PEM formatted block in Register() --- src/github.com/matrix-org/go-neb/api.go | 4 + src/github.com/matrix-org/go-neb/goneb.go | 1 + .../matrix-org/go-neb/realms/github/github.go | 4 + .../matrix-org/go-neb/realms/jira/jira.go | 87 +++++++++++++++++++ .../matrix-org/go-neb/types/types.go | 1 + 5 files changed, 97 insertions(+) create mode 100644 src/github.com/matrix-org/go-neb/realms/jira/jira.go diff --git a/src/github.com/matrix-org/go-neb/api.go b/src/github.com/matrix-org/go-neb/api.go index ea87876..620fc56 100644 --- a/src/github.com/matrix-org/go-neb/api.go +++ b/src/github.com/matrix-org/go-neb/api.go @@ -98,6 +98,10 @@ func (h *configureAuthRealmHandler) OnIncomingRequest(req *http.Request) (interf return nil, &errors.HTTPError{err, "Error parsing config JSON", 400} } + if err := realm.Register(); err != nil { + return nil, &errors.HTTPError{err, "Error registering auth realm", 400} + } + oldRealm, err := h.db.StoreAuthRealm(realm) if err != nil { return nil, &errors.HTTPError{err, "Error storing realm", 500} diff --git a/src/github.com/matrix-org/go-neb/goneb.go b/src/github.com/matrix-org/go-neb/goneb.go index 1f59d32..9dba6ba 100644 --- a/src/github.com/matrix-org/go-neb/goneb.go +++ b/src/github.com/matrix-org/go-neb/goneb.go @@ -5,6 +5,7 @@ import ( "github.com/matrix-org/go-neb/clients" "github.com/matrix-org/go-neb/database" _ "github.com/matrix-org/go-neb/realms/github" + _ "github.com/matrix-org/go-neb/realms/jira" "github.com/matrix-org/go-neb/server" _ "github.com/matrix-org/go-neb/services/echo" _ "github.com/matrix-org/go-neb/services/github" diff --git a/src/github.com/matrix-org/go-neb/realms/github/github.go b/src/github.com/matrix-org/go-neb/realms/github/github.go index 9b88d5b..f192495 100644 --- a/src/github.com/matrix-org/go-neb/realms/github/github.go +++ b/src/github.com/matrix-org/go-neb/realms/github/github.go @@ -53,6 +53,10 @@ func (r *githubRealm) Type() string { return "github" } +func (r *githubRealm) Register() error { + return nil +} + func (r *githubRealm) RequestAuthSession(userID string, req json.RawMessage) interface{} { state, err := randomString(10) if err != nil { 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 new file mode 100644 index 0000000..51edf57 --- /dev/null +++ b/src/github.com/matrix-org/go-neb/realms/jira/jira.go @@ -0,0 +1,87 @@ +package realms + +import ( + "crypto/rsa" + "crypto/x509" + "encoding/json" + "encoding/pem" + "errors" + log "github.com/Sirupsen/logrus" + "github.com/matrix-org/go-neb/types" + "net/http" +) + +type jiraRealm struct { + id string + ConsumerName string + ConsumerKey string + ConsumerSecret string + PrivateKeyPEM string +} + +func (r *jiraRealm) ID() string { + return r.id +} + +func (r *jiraRealm) Type() string { + return "jira" +} + +func (r *jiraRealm) Register() error { + if r.ConsumerName == "" || r.ConsumerKey == "" || r.ConsumerSecret == "" || r.PrivateKeyPEM == "" { + return errors.New("ConsumerName, ConsumerKey, ConsumerSecret, PrivateKeyPEM must be specified.") + } + // Make sure the private key PEM is actually a private key. + _, err := loadPrivateKey(r.PrivateKeyPEM) + if err != nil { + return err + } + return nil +} + +func (r *jiraRealm) RequestAuthSession(userID string, req json.RawMessage) interface{} { + reqAuth := struct { + JIRAURL string + }{} + if err := json.Unmarshal(req, reqAuth); err != nil { + log.WithError(err).Print("Error parsing request JSON") + return nil + } + if reqAuth.JIRAURL == "" { + log.Print("Missing JIRAURL") + return nil + } + // TODO: Check to see if JIRA endpoint is valid and known + return nil +} + +func (r *jiraRealm) OnReceiveRedirect(w http.ResponseWriter, req *http.Request) { + +} + +func (r *jiraRealm) AuthSession(id, userID, realmID string) types.AuthSession { + return nil +} + +func loadPrivateKey(privKeyPEM string) (*rsa.PrivateKey, error) { + // Decode PEM to grab the private key type + block, _ := pem.Decode([]byte(privKeyPEM)) + if block == nil { + return nil, errors.New("No PEM formatted block found") + } + + // TODO: Handle passwords on private keys. + // decBytes, err = x509.DecryptPEMBlock(block, []byte{}) // no pass + + priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + return priv, nil +} + +func init() { + types.RegisterAuthRealm(func(realmID string) types.AuthRealm { + return &jiraRealm{id: realmID} + }) +} diff --git a/src/github.com/matrix-org/go-neb/types/types.go b/src/github.com/matrix-org/go-neb/types/types.go index ed3197d..c010064 100644 --- a/src/github.com/matrix-org/go-neb/types/types.go +++ b/src/github.com/matrix-org/go-neb/types/types.go @@ -81,6 +81,7 @@ func CreateService(serviceID, serviceType string) Service { type AuthRealm interface { ID() string Type() string + Register() error OnReceiveRedirect(w http.ResponseWriter, req *http.Request) AuthSession(id, userID, realmID string) AuthSession RequestAuthSession(userID string, config json.RawMessage) interface{} From a0d3180ba83891720777c02bc88fdcf44f34c614 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 9 Aug 2016 17:50:14 +0100 Subject: [PATCH 2/3] Parse out the public key --- .../matrix-org/go-neb/realms/jira/jira.go | 49 ++++++++++++++----- 1 file changed, 36 insertions(+), 13 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 51edf57..2b1e90e 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 @@ -13,9 +13,12 @@ import ( type jiraRealm struct { id string + privateKey *rsa.PrivateKey + JIRAEndpoint string ConsumerName string ConsumerKey string ConsumerSecret string + PublicKeyPEM string // clobbered based on PrivateKeyPEM PrivateKeyPEM string } @@ -31,27 +34,19 @@ func (r *jiraRealm) Register() error { if r.ConsumerName == "" || r.ConsumerKey == "" || r.ConsumerSecret == "" || r.PrivateKeyPEM == "" { return errors.New("ConsumerName, ConsumerKey, ConsumerSecret, PrivateKeyPEM must be specified.") } + log.Print("Registering..") // Make sure the private key PEM is actually a private key. - _, err := loadPrivateKey(r.PrivateKeyPEM) + err := r.parsePrivateKey() if err != nil { return err } + + // TODO: Check to see if JIRA endpoint is valid and known + return nil } func (r *jiraRealm) RequestAuthSession(userID string, req json.RawMessage) interface{} { - reqAuth := struct { - JIRAURL string - }{} - if err := json.Unmarshal(req, reqAuth); err != nil { - log.WithError(err).Print("Error parsing request JSON") - return nil - } - if reqAuth.JIRAURL == "" { - log.Print("Missing JIRAURL") - return nil - } - // TODO: Check to see if JIRA endpoint is valid and known return nil } @@ -63,6 +58,20 @@ func (r *jiraRealm) AuthSession(id, userID, realmID string) types.AuthSession { return nil } +func (r *jiraRealm) parsePrivateKey() error { + pk, err := loadPrivateKey(r.PrivateKeyPEM) + if err != nil { + return err + } + pub, err := publicKeyAsPEM(pk) + if err != nil { + return err + } + r.PublicKeyPEM = pub + r.privateKey = pk + return nil +} + func loadPrivateKey(privKeyPEM string) (*rsa.PrivateKey, error) { // Decode PEM to grab the private key type block, _ := pem.Decode([]byte(privKeyPEM)) @@ -80,6 +89,20 @@ func loadPrivateKey(privKeyPEM string) (*rsa.PrivateKey, error) { return priv, nil } +func publicKeyAsPEM(pkey *rsa.PrivateKey) (string, error) { + // https://github.com/golang-samples/cipher/blob/master/crypto/rsa_keypair.go + der, err := x509.MarshalPKIXPublicKey(&pkey.PublicKey) + if err != nil { + return "", err + } + block := pem.Block{ + Type: "PUBLIC KEY", + Headers: nil, + Bytes: der, + } + return string(pem.EncodeToMemory(&block)), nil +} + func init() { types.RegisterAuthRealm(func(realmID string) types.AuthRealm { return &jiraRealm{id: realmID} From 5e375283c209be95da75c6614c5a55c17b009bdf Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 10 Aug 2016 09:48:04 +0100 Subject: [PATCH 3/3] Remove password TODO --- src/github.com/matrix-org/go-neb/realms/jira/jira.go | 3 --- 1 file changed, 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 2b1e90e..ca0f892 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 @@ -79,9 +79,6 @@ func loadPrivateKey(privKeyPEM string) (*rsa.PrivateKey, error) { return nil, errors.New("No PEM formatted block found") } - // TODO: Handle passwords on private keys. - // decBytes, err = x509.DecryptPEMBlock(block, []byte{}) // no pass - priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return nil, err