Skip to content

Commit

Permalink
Merge pull request #4149 from nickmango/feature/icla-ccla-docsign-go
Browse files Browse the repository at this point in the history
[#4002] Docusign API - Golang
  • Loading branch information
nickmango authored Oct 12, 2023
2 parents dcce966 + b062627 commit 680eced
Show file tree
Hide file tree
Showing 9 changed files with 439 additions and 200 deletions.
36 changes: 12 additions & 24 deletions cla-backend-go/swagger/cla.v2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4137,7 +4137,7 @@ paths:
- name: input
in: body
schema:
$ref: '#/definitions/icla-signature-input'
$ref: '#/definitions/individual-signature-input'
required: true
responses:
'200':
Expand Down Expand Up @@ -5527,38 +5527,26 @@ definitions:
corporate-contributor:
$ref: './common/corporate-contributor.yaml'

icla-signature-input:
individual-signature-input:
type: object
required:
- project_sfid
- company_sfid
- project_id
- user_id
properties:
project_sfid:
type: string
example: 'a0941000005ouJFAAY'
description: salesforce id of the project
company_sfid:
type: string
example: '0014100000Te0fMAAR'
description: salesforce id of the company
send_as_email:
type: boolean
example: false
description: send signing request as email. This should be set to true when requestor is not signatory.
authority_name:
project_id:
type: string
example: "Derk Miyamoto"
description: the name of the CLA signatory
minLength: 2
maxLength: 255
authority_email:
$ref: './common/properties/email.yaml'
description: the email of the CLA Signatory
example: "e1e30240-a722-4c82-a648-121681d959c7"
return_url:
type: string
example: 'https://corporate.dev.lfcla.com/#/company/eb4d7d71-693f-4047-bf8d-10d0e7764969'
description: on signing the document, page will get redirected to this url. This is valid only when send_as_email is false
format: uri
return_url_type:
type: string
example: Gerrit/Github/GitLab. Optional depending on presence of return_url
user_id:
type: string
example: "e1e30240-a722-4c82-a648-121681d959c7"


corporate-signature-input:
Expand Down
102 changes: 0 additions & 102 deletions cla-backend-go/v2/docusign_auth/auth.go

This file was deleted.

47 changes: 0 additions & 47 deletions cla-backend-go/v2/main/main.go

This file was deleted.

2 changes: 1 addition & 1 deletion cla-backend-go/v2/project/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ func buildSFProjectSummary(sfProject *v2ProjectServiceModels.ProjectOutputDetail
return &models.SfProjectSummary{
EntityName: utils.StringValue(sfProject.EntityName),
EntityType: sfProject.EntityType,
Funding: sfProject.Funding,
Funding: *sfProject.Funding,
ID: sfProject.ID,
LfSupported: sfProject.LFSponsored,
Name: sfProject.Name,
Expand Down
78 changes: 73 additions & 5 deletions cla-backend-go/v2/sign/docusign.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,82 @@ package sign

import (
"context"
"log"
"encoding/json"
"errors"
"io"
"net/http"
"strings"

log "github.com/communitybridge/easycla/cla-backend-go/logging"
"github.com/communitybridge/easycla/cla-backend-go/utils"
"github.com/sirupsen/logrus"
)

// getAccessToken retrieves an access token for the DocuSign API using a JWT assertion.
func (s *service) getAccessToken(ctx context.Context) (string, error) {
f := logrus.Fields{
"functionName": "sign.getAccessToken",
"functionName": "v2.getAccessToken",
utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
}

jwtAssertion, err := jwtToken()
if err != nil {
log.WithFields(f).WithError(err).Warnf("problem generating the JWT token")
return "", err
}

// Get the access token
jwtAssertion, jwterr := jwtToken()
}
// Create the request
tokenRequestBody := DocuSignGetTokenRequest{
GrantType: "urn:ietf:params:oauth:grant-type:jwt-bearer",
Assertion: jwtAssertion,
}

tokenRequestBodyJSON, err := json.Marshal(tokenRequestBody)
if err != nil {
log.WithFields(f).WithError(err).Warnf("problem marshalling the token request body")
return "", err
}

url := utils.GetProperty("DOCUSIGN_AUTH_SERVER") + "/oauth/token"
req, err := http.NewRequest("POST", url, strings.NewReader(string(tokenRequestBodyJSON)))
if err != nil {
log.WithFields(f).WithError(err).Warnf("problem creating the HTTP request")
return "", err
}

req.Header.Add("Content-Type", "application/json")
req.Header.Add("Accept", "application/json")

// Make the request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.WithFields(f).WithError(err).Warnf("problem making the HTTP request")
return "", err
}

defer resp.Body.Close()

// Parse the response
responsePayload, err := io.ReadAll(resp.Body)
if err != nil {
log.WithFields(f).WithError(err).Warnf("problem reading the response body")
return "", err
}

if resp.StatusCode != http.StatusOK {
log.WithFields(f).Warnf("problem making the HTTP request - status code: %d", resp.StatusCode)
return "", errors.New("problem making the HTTP request")
}

var tokenResponse DocuSignGetTokenResponse

err = json.Unmarshal(responsePayload, &tokenResponse)
if err != nil {
log.WithFields(f).WithError(err).Warnf("problem unmarshalling the response body")
return "", err
}

return tokenResponse.AccessToken, nil

}
9 changes: 4 additions & 5 deletions cla-backend-go/v2/sign/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"github.com/communitybridge/easycla/cla-backend-go/utils"
"github.com/communitybridge/easycla/cla-backend-go/v2/organization-service/client/organizations"
"github.com/go-openapi/runtime/middleware"

)

// Configure API call
Expand Down Expand Up @@ -85,10 +84,10 @@ func Configure(api *operations.EasyclaAPI, service Service) {
f := logrus.Fields{
"functionName": "v2.sign.handlers.SignRequestIndividualSignatureHandler",
utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
"CompanyID": params.Input.CompanySfid,
"ProjectSFID": params.Input.ProjectSfid,
"authorityName": params.Input.AuthorityName,
"authorityEmail": params.Input.AuthorityEmail,
"projectID": params.Input.ProjectID,
"returnURL": params.Input.ReturnURL,
"returnURLType": params.Input.ReturnURLType,
"userID": params.Input.UserID,
}
log.WithFields(f).Debug("processing request")
resp, err := service.RequestIndividualSignature(ctx, params.Input)
Expand Down
51 changes: 47 additions & 4 deletions cla-backend-go/v2/sign/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,57 @@
package sign

import (
"time"

log "github.com/communitybridge/easycla/cla-backend-go/logging"
"github.com/communitybridge/easycla/cla-backend-go/utils"
"github.com/golang-jwt/jwt"
"github.com/sirupsen/logrus"
)

const

func jwtToken() (string, error) {
f := logrus.Fields{
"functionName": "v2.sign.jwtToken",
}

claims := jwt.MapClaims{
"iss": ,
"iss": utils.GetProperty("DOCUSIGN_INTEGRATION_KEY"), // integration key / client_id
"sub": utils.GetProperty("DOCUSIGN_INTEGRATION_USER_ID"), // user_id, in PROD should be the EasyCLA Admin user account
"aud": utils.GetProperty("DOCUSIGN_AUTH_SERVER"), // account.docusign.com or account-d.docusign.com (for dev)
"iat": time.Now().Unix(),
"exp": time.Now().Add(time.Hour).Unix(), // one hour appears to be the max, minus 60 seconds
"scope": "signature impersonation",
}
// log.WithFields(f).Debugf("claims: %+v", claims)

token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)

// DEBUG - remove
// log.WithFields(f).Debugf("integration key (iss) : %s", utils.GetProperty("DOCUSIGN_INTEGRATION_KEY"))
// log.WithFields(f).Debugf("integration user (sub) : %s", utils.GetProperty("DOCUSIGN_INTEGRATION_USER_ID"))
// log.WithFields(f).Debugf("integration host : %s", getDocuSignAccountHost())

token.Header["alg"] = "RS256"
token.Header["typ"] = "JWT"

//publicKey, publicKeyErr := jwt.ParseRSAPublicKeyFromPEM([]byte(utils.GetProperty("DOCUSIGN_RSA_PUBLIC_KEY")))
//if publicKeyErr != nil {
// log.WithFields(f).WithError(publicKeyErr).Warnf("problem decoding docusign public key")
// return "", publicKeyErr
//}
privateKey, privateKeyErr := jwt.ParseRSAPrivateKeyFromPEM([]byte(utils.GetProperty("DOCUSIGN_RSA_PRIVATE_KEY")))
// privateKey, privateKeyErr := jwt.ParseRSAPrivateKeyFromPEM([]byte(docusignPrivateKey))
if privateKeyErr != nil {
log.WithFields(f).WithError(privateKeyErr).Warnf("problem decoding docusign private key")
return "", privateKeyErr
}
}
// log.WithFields(f).Debugf("private key: %s", utils.GetProperty("DOCUSIGN_RSA_PRIVATE_KEY"))

signedToken, signedTokenErr := token.SignedString(privateKey)
if signedTokenErr != nil {
log.WithFields(f).WithError(signedTokenErr).Warnf("problem generating the signed token")
}
// log.WithFields(f).Debugf("signed token: %s", signedToken)

return signedToken, signedTokenErr
}
Loading

0 comments on commit 680eced

Please sign in to comment.