mirror of https://github.com/harness/drone.git
feat: [CODE-2886]: jira auth support (#3119)
parent
1e18e289d8
commit
c7f7ade6b6
|
@ -20,8 +20,16 @@ import (
|
|||
)
|
||||
|
||||
type Preprocessor interface {
|
||||
PreprocessCreateInput(enum.PrincipalType, *types.WebhookCreateInput) (enum.WebhookType, error)
|
||||
PreprocessUpdateInput(enum.PrincipalType, *types.WebhookUpdateInput) (enum.WebhookType, error)
|
||||
PreprocessCreateInput(
|
||||
enum.PrincipalType,
|
||||
*types.WebhookCreateInput,
|
||||
*types.WebhookSignatureMetadata,
|
||||
) (enum.WebhookType, error)
|
||||
PreprocessUpdateInput(
|
||||
enum.PrincipalType,
|
||||
*types.WebhookUpdateInput,
|
||||
*types.WebhookSignatureMetadata,
|
||||
) (enum.WebhookType, error)
|
||||
PreprocessFilter(enum.PrincipalType, *types.WebhookFilter)
|
||||
IsInternalCall(enum.PrincipalType) bool
|
||||
}
|
||||
|
@ -33,6 +41,7 @@ type NoopPreprocessor struct {
|
|||
func (p NoopPreprocessor) PreprocessCreateInput(
|
||||
enum.PrincipalType,
|
||||
*types.WebhookCreateInput,
|
||||
*types.WebhookSignatureMetadata,
|
||||
) (enum.WebhookType, error) {
|
||||
return enum.WebhookTypeExternal, nil
|
||||
}
|
||||
|
@ -41,6 +50,7 @@ func (p NoopPreprocessor) PreprocessCreateInput(
|
|||
func (p NoopPreprocessor) PreprocessUpdateInput(
|
||||
enum.PrincipalType,
|
||||
*types.WebhookUpdateInput,
|
||||
*types.WebhookSignatureMetadata,
|
||||
) (enum.WebhookType, error) {
|
||||
return enum.WebhookTypeExternal, nil
|
||||
}
|
||||
|
|
|
@ -29,13 +29,14 @@ func (c *Controller) CreateRepo(
|
|||
session *auth.Session,
|
||||
repoRef string,
|
||||
in *types.WebhookCreateInput,
|
||||
signatureData *types.WebhookSignatureMetadata,
|
||||
) (*types.Webhook, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to acquire access to the repo: %w", err)
|
||||
}
|
||||
|
||||
typ, err := c.preprocessor.PreprocessCreateInput(session.Principal.Type, in)
|
||||
typ, err := c.preprocessor.PreprocessCreateInput(session.Principal.Type, in, signatureData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to preprocess create input: %w", err)
|
||||
}
|
||||
|
|
|
@ -30,18 +30,17 @@ func (c *Controller) UpdateRepo(
|
|||
repoRef string,
|
||||
webhookIdentifier string,
|
||||
in *types.WebhookUpdateInput,
|
||||
signatureData *types.WebhookSignatureMetadata,
|
||||
) (*types.Webhook, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to acquire access to the repo: %w", err)
|
||||
}
|
||||
|
||||
typ, err := c.preprocessor.PreprocessUpdateInput(session.Principal.Type, in)
|
||||
typ, err := c.preprocessor.PreprocessUpdateInput(session.Principal.Type, in, signatureData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to preprocess update input: %w", err)
|
||||
}
|
||||
|
||||
return c.webhookService.Update(
|
||||
ctx, repo.ID, enum.WebhookParentRepo, webhookIdentifier, typ, in,
|
||||
)
|
||||
return c.webhookService.Update(ctx, repo.ID, enum.WebhookParentRepo, webhookIdentifier, typ, in)
|
||||
}
|
||||
|
|
|
@ -29,20 +29,19 @@ func (c *Controller) CreateSpace(
|
|||
session *auth.Session,
|
||||
spaceRef string,
|
||||
in *types.WebhookCreateInput,
|
||||
signatureData *types.WebhookSignatureMetadata,
|
||||
) (*types.Webhook, error) {
|
||||
space, err := c.getSpaceCheckAccess(ctx, session, spaceRef, enum.PermissionSpaceEdit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to acquire access to space: %w", err)
|
||||
}
|
||||
|
||||
internal, err := c.preprocessor.PreprocessCreateInput(session.Principal.Type, in)
|
||||
internal, err := c.preprocessor.PreprocessCreateInput(session.Principal.Type, in, signatureData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to preprocess create input: %w", err)
|
||||
}
|
||||
|
||||
hook, err := c.webhookService.Create(
|
||||
ctx, session.Principal.ID, space.ID, enum.WebhookParentSpace, internal, in,
|
||||
)
|
||||
hook, err := c.webhookService.Create(ctx, session.Principal.ID, space.ID, enum.WebhookParentSpace, internal, in)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create webhook: %w", err)
|
||||
}
|
||||
|
|
|
@ -30,13 +30,14 @@ func (c *Controller) UpdateSpace(
|
|||
spaceRef string,
|
||||
webhookIdentifier string,
|
||||
in *types.WebhookUpdateInput,
|
||||
signatureData *types.WebhookSignatureMetadata,
|
||||
) (*types.Webhook, error) {
|
||||
space, err := c.getSpaceCheckAccess(ctx, session, spaceRef, enum.PermissionSpaceEdit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to acquire access to space: %w", err)
|
||||
}
|
||||
|
||||
typ, err := c.preprocessor.PreprocessUpdateInput(session.Principal.Type, in)
|
||||
typ, err := c.preprocessor.PreprocessUpdateInput(session.Principal.Type, in, signatureData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to preprocess update input: %w", err)
|
||||
}
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
package webhook
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/app/api/controller/webhook"
|
||||
|
@ -29,6 +31,11 @@ func HandleCreateRepo(webhookCtrl *webhook.Controller) http.HandlerFunc {
|
|||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
bodyBytes, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
repoRef, err := request.GetRepoRefFromPath(r)
|
||||
if err != nil {
|
||||
|
@ -37,13 +44,22 @@ func HandleCreateRepo(webhookCtrl *webhook.Controller) http.HandlerFunc {
|
|||
}
|
||||
|
||||
in := new(types.WebhookCreateInput)
|
||||
err = json.NewDecoder(r.Body).Decode(in)
|
||||
readerCloser := io.NopCloser(bytes.NewReader(bodyBytes))
|
||||
err = json.NewDecoder(readerCloser).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
hook, err := webhookCtrl.CreateRepo(ctx, session, repoRef, in)
|
||||
var signatureData *types.WebhookSignatureMetadata
|
||||
signature := request.GetSignatureFromHeaderOrDefault(r, "")
|
||||
if signature != "" {
|
||||
signatureData = new(types.WebhookSignatureMetadata)
|
||||
signatureData.Signature = signature
|
||||
signatureData.BodyBytes = bodyBytes
|
||||
}
|
||||
|
||||
hook, err := webhookCtrl.CreateRepo(ctx, session, repoRef, in, signatureData)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
package webhook
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/app/api/controller/webhook"
|
||||
|
@ -29,6 +31,11 @@ func HandleUpdateRepo(webhookCtrl *webhook.Controller) http.HandlerFunc {
|
|||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
bodyBytes, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
repoRef, err := request.GetRepoRefFromPath(r)
|
||||
if err != nil {
|
||||
|
@ -43,13 +50,22 @@ func HandleUpdateRepo(webhookCtrl *webhook.Controller) http.HandlerFunc {
|
|||
}
|
||||
|
||||
in := new(types.WebhookUpdateInput)
|
||||
err = json.NewDecoder(r.Body).Decode(in)
|
||||
readerCloser := io.NopCloser(bytes.NewReader(bodyBytes))
|
||||
err = json.NewDecoder(readerCloser).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
hook, err := webhookCtrl.UpdateRepo(ctx, session, repoRef, webhookIdentifier, in)
|
||||
var signatureData *types.WebhookSignatureMetadata
|
||||
signature := request.GetSignatureFromHeaderOrDefault(r, "")
|
||||
if signature != "" {
|
||||
signatureData = new(types.WebhookSignatureMetadata)
|
||||
signatureData.Signature = signature
|
||||
signatureData.BodyBytes = bodyBytes
|
||||
}
|
||||
|
||||
hook, err := webhookCtrl.UpdateRepo(ctx, session, repoRef, webhookIdentifier, in, signatureData)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
package webhook
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/app/api/controller/webhook"
|
||||
|
@ -29,6 +31,11 @@ func HandleCreateSpace(webhookCtrl *webhook.Controller) http.HandlerFunc {
|
|||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
bodyBytes, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
spaceRef, err := request.GetSpaceRefFromPath(r)
|
||||
if err != nil {
|
||||
|
@ -37,13 +44,22 @@ func HandleCreateSpace(webhookCtrl *webhook.Controller) http.HandlerFunc {
|
|||
}
|
||||
|
||||
in := new(types.WebhookCreateInput)
|
||||
err = json.NewDecoder(r.Body).Decode(in)
|
||||
readerCloser := io.NopCloser(bytes.NewReader(bodyBytes))
|
||||
err = json.NewDecoder(readerCloser).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
hook, err := webhookCtrl.CreateSpace(ctx, session, spaceRef, in)
|
||||
var signatureData *types.WebhookSignatureMetadata
|
||||
signature := request.GetSignatureFromHeaderOrDefault(r, "")
|
||||
if signature != "" {
|
||||
signatureData = new(types.WebhookSignatureMetadata)
|
||||
signatureData.Signature = signature
|
||||
signatureData.BodyBytes = bodyBytes
|
||||
}
|
||||
|
||||
hook, err := webhookCtrl.CreateSpace(ctx, session, spaceRef, in, signatureData)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
package webhook
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/app/api/controller/webhook"
|
||||
|
@ -29,6 +31,11 @@ func HandleUpdateSpace(webhookCtrl *webhook.Controller) http.HandlerFunc {
|
|||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
bodyBytes, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
spaceRef, err := request.GetSpaceRefFromPath(r)
|
||||
if err != nil {
|
||||
|
@ -43,13 +50,22 @@ func HandleUpdateSpace(webhookCtrl *webhook.Controller) http.HandlerFunc {
|
|||
}
|
||||
|
||||
in := new(types.WebhookUpdateInput)
|
||||
err = json.NewDecoder(r.Body).Decode(in)
|
||||
readerCloser := io.NopCloser(bytes.NewReader(bodyBytes))
|
||||
err = json.NewDecoder(readerCloser).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
hook, err := webhookCtrl.UpdateSpace(ctx, session, spaceRef, webhookIdentifier, in)
|
||||
var signatureData *types.WebhookSignatureMetadata
|
||||
signature := request.GetSignatureFromHeaderOrDefault(r, "")
|
||||
if signature != "" {
|
||||
signatureData = new(types.WebhookSignatureMetadata)
|
||||
signatureData.Signature = signature
|
||||
signatureData.BodyBytes = bodyBytes
|
||||
}
|
||||
|
||||
hook, err := webhookCtrl.UpdateSpace(ctx, session, spaceRef, webhookIdentifier, in, signatureData)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
|
|
|
@ -67,6 +67,8 @@ const (
|
|||
|
||||
HeaderIfNoneMatch = "If-None-Match"
|
||||
HeaderETag = "ETag"
|
||||
|
||||
HeaderSignature = "Signature"
|
||||
)
|
||||
|
||||
// GetOptionalRemainderFromPath returns the remainder ("*") from the path or an empty string if it doesn't exist.
|
||||
|
@ -239,3 +241,7 @@ func GetDeletedAtFromQuery(r *http.Request) (int64, bool, error) {
|
|||
func GetIfNoneMatchFromHeader(r *http.Request) (string, bool) {
|
||||
return GetHeader(r, HeaderIfNoneMatch)
|
||||
}
|
||||
|
||||
func GetSignatureFromHeaderOrDefault(r *http.Request, dflt string) string {
|
||||
return GetHeaderOrDefault(r, HeaderSignature, dflt)
|
||||
}
|
||||
|
|
|
@ -17,9 +17,6 @@ package webhook
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -28,6 +25,7 @@ import (
|
|||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/crypto"
|
||||
"github.com/harness/gitness/store"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
@ -354,7 +352,7 @@ func (s *Service) prepareHTTPRequest(ctx context.Context, execution *types.Webho
|
|||
return nil, fmt.Errorf("failed to decrypt webhook secret: %w", err)
|
||||
}
|
||||
var hmac string
|
||||
hmac, err = generateHMACSHA256(bBuff.Bytes(), []byte(decryptedSecret))
|
||||
hmac, err = crypto.GenerateHMACSHA256(bBuff.Bytes(), []byte(decryptedSecret))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate SHA256 based HMAC: %w", err)
|
||||
}
|
||||
|
@ -475,20 +473,3 @@ func handleWebhookResponse(execution *types.WebhookExecution, resp *http.Respons
|
|||
return fmt.Errorf("received response with unsupported status code %d", code)
|
||||
}
|
||||
}
|
||||
|
||||
// generateHMACSHA256 generates a new HMAC using SHA256 as hash function.
|
||||
func generateHMACSHA256(data []byte, key []byte) (string, error) {
|
||||
h := hmac.New(sha256.New, key)
|
||||
|
||||
// write all data into hash
|
||||
_, err := h.Write(data)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to write data into hash: %w", err)
|
||||
}
|
||||
|
||||
// sum hash to final value
|
||||
macBytes := h.Sum(nil)
|
||||
|
||||
// encode MAC as hexadecimal
|
||||
return hex.EncodeToString(macBytes), nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// GenerateHMACSHA256 generates a new HMAC using SHA256 as hash function.
|
||||
func GenerateHMACSHA256(data []byte, key []byte) (string, error) {
|
||||
h := hmac.New(sha256.New, key)
|
||||
|
||||
// write all data into hash
|
||||
_, err := h.Write(data)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to write data into hash: %w", err)
|
||||
}
|
||||
|
||||
// sum hash to final value
|
||||
macBytes := h.Sum(nil)
|
||||
|
||||
// encode MAC as hexadecimal
|
||||
return hex.EncodeToString(macBytes), nil
|
||||
}
|
||||
|
||||
func IsShaEqual(key1, key2 string) bool {
|
||||
return hmac.Equal([]byte(key1), []byte(key2))
|
||||
}
|
|
@ -83,6 +83,11 @@ type WebhookCreateInput struct {
|
|||
Triggers []enum.WebhookTrigger `json:"triggers"`
|
||||
}
|
||||
|
||||
type WebhookSignatureMetadata struct {
|
||||
Signature string
|
||||
BodyBytes []byte
|
||||
}
|
||||
|
||||
type WebhookUpdateInput struct {
|
||||
// TODO [CODE-1363]: remove after identifier migration.
|
||||
UID *string `json:"uid" deprecated:"true"`
|
||||
|
|
Loading…
Reference in New Issue