Last active
April 19, 2020 07:32
-
-
Save bsathishciv/cee4069ac807ff77fe19274e41b856e4 to your computer and use it in GitHub Desktop.
Salesforce authentication module in Go lang
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package authentication | |
import ( | |
"bufio" | |
"encoding/json" | |
"errors" | |
"io/ioutil" | |
"net/http" | |
"net/url" | |
"os" | |
"strings" | |
"time" | |
"github.com/dgrijalva/jwt-go" | |
) | |
const grantType string = "urn:ietf:params:oauth:grant-type:jwt-bearer" | |
const consumerKet string = "3MVG9ZLXXXXXXXXXXXXXXXXXXXXXXX_kyc" // replace with consumer key of the connected app | |
/ AuthenticationRequest - wrapper to hold auth request data | |
// OAuth 2.0. protocol is used | |
type AuthenticationRequest struct { | |
URL string `json:"url"` | |
Username string `json:"username"` | |
} | |
type authenticationResponse struct { | |
Token string `json:"access_token"` | |
InstanceURL string `json:"instance_url"` | |
ID string `json:"id"` | |
TokenType string `json:"token_type"` | |
IssuedAt string `json:"issued_at"` | |
Signature string `json:"signature"` | |
} | |
type claims struct { | |
jwt.StandardClaims | |
} | |
type AuthenticationResponse interface { | |
GetToken() string | |
GetInstanceURL() string | |
GetID() string | |
GetTokenType() string | |
GetIssuedAt() string | |
GetSignature() string | |
} | |
// GetToken returns the authenication token. | |
func (response authenticationResponse) GetToken() string { return response.Token } | |
// GetInstanceURL returns the Salesforce instance URL to use with the authenication information. | |
func (response authenticationResponse) GetInstanceURL() string { return response.InstanceURL } | |
// GetID returns the Salesforce ID of the authenication. | |
func (response authenticationResponse) GetID() string { return response.ID } | |
// GetTokenType returns the authenication token type. | |
func (response authenticationResponse) GetTokenType() string { return response.TokenType } | |
// GetIssuedAt returns the time when the token was issued. | |
func (response authenticationResponse) GetIssuedAt() string { return response.IssuedAt } | |
// GetSignature returns the signature of the authenication. | |
func (response authenticationResponse) GetSignature() string { return response.Signature } | |
// Authenicate will exchange the JWT signed request for access token. | |
func Authenicate(request AuthenticationRequest, client *http.Client) (AuthenticationResponse, error) { | |
privateKeyFile, err := os.Open("private_key.pem") // Give a relative reference to this file. | |
if err != nil { | |
return nil, err | |
} | |
pemfileinfo, _ := privateKeyFile.Stat() | |
var size int64 = pemfileinfo.Size() | |
pembytes := make([]byte, size) | |
buffer := bufio.NewReader(privateKeyFile) | |
_, err = buffer.Read(pembytes) | |
pemData := []byte(pembytes) | |
privateKeyFile.Close() // close file | |
expirationTime := time.Now().Add(3 * time.Minute) | |
claims := &claims{ | |
StandardClaims: jwt.StandardClaims{ | |
// In JWT, the expiry time is expressed as unix milliseconds | |
ExpiresAt: expirationTime.Unix(), // type int64 | |
Audience: request.URL, // "https://test.salesforce.com" || "https://login.salesforce.com" | |
Issuer: request.ClientID, // consumer key of the connected app, hardcoded | |
Subject: request.Username, // username of the salesforce user, whose profile is added to the connected app | |
}, | |
} | |
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) | |
signKey, err := jwt.ParseRSAPrivateKeyFromPEM(pemData) // parse the RSA key | |
tokenString, err := token.SignedString(signKey) // sign the claims with private key | |
form := url.Values{} | |
form.Add("grant_type", grantType) | |
form.Add("assertion", tokenString) | |
url := request.URL + "/services/oauth2/token" // token endpoint for getting access token | |
log.Info("Performing request using url: " + url) | |
httpRequest, err := http.NewRequest("POST", url, strings.NewReader(form.Encode())) | |
if err != nil { | |
return nil, err | |
} | |
httpRequest.Header.Add("Content-Type", "application/x-www-form-urlencoded") | |
response, respErr := client.Do(httpRequest) | |
if respErr != nil { | |
return nil, respErr | |
} | |
if response.StatusCode >= 300 { | |
return nil, errors.New(response.Status) | |
} | |
body, bodyErr := ioutil.ReadAll(response.Body) | |
if bodyErr != nil { | |
return nil, bodyErr | |
} | |
var jsonResponse authenticationResponse | |
unMarshallErr := json.Unmarshal(body, &jsonResponse) | |
if unMarshallErr != nil { | |
return nil, unMarshallErr | |
} | |
return jsonResponse, nil | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment