Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#4002] Docusign API - Golang #4149

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading