Skip to content

Instantly share code, notes, and snippets.

@simonjefford
Last active August 29, 2015 14:04
Show Gist options
  • Save simonjefford/af965f76a75a7ce0f0ea to your computer and use it in GitHub Desktop.
Save simonjefford/af965f76a75a7ce0f0ea to your computer and use it in GitHub Desktop.
Salesforce
Raw Token
---------
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjE5MCJ9.eyJleHAiOjE0MDY4MTkwODMsInN1YiI6Imh0dHBzOi8vbG9naW4uc2FsZXNmb3JjZS5jb20vaWQvMDBEMjAwMDAwMDBuVjBhRUFFLzAwNTIwMDAwMDAzaEhsREFBVSIsImF0X2hhc2giOiItZU4tdzgteFZzcm4wVHJKQzh0THp3IiwiYXVkIjoiM01WRzlXdFdTS1VERy54NndzZUhDWklkX055aDVaUU9CZWpKZjRONE55VF9OaVJUd2FsbE5lUjVLMFZ4dzFiWGFJY0JMOWNob2tiQlhpYmtTR01ZUiIsImlzcyI6Imh0dHBzOi8vbG9naW4uc2FsZXNmb3JjZS5jb20iLCJpYXQiOjE0MDY4MTg5NjN9.MnFuklB18wjGotkaWPqcUMb0cRT57UfsPCYUUmJVUur5YNFtimQz6l-7iBzKxow1J6nj-7YRyIbwID5TcXFesnP_aMP62rPNFOIZ-nMfYcoG0FnnIxq5s-thfk0jIJSpv_Teb4p1EdBzKfKKb9rxJ4FGP5AlLloJTfqpU17P82TBIBGKPiT8o19DWYUmdn6kUuzM04rSDc2OaCfb4OqodgzpnBXFbXwpUZi15wqZ97NaGBG6turatUguP3wHRcugD8uXqu0aBzqWoUztAxloQiCIS7mPTmO7EYZcUybZUfKUFPygipN_CrgPzGLtUWTQpBoZ-w8xcjTWzrgUBWW1J6o2FN3Dqr7ecgcfxCCSSTFBmDg3wfp9MOb3ztJoN4MFM-IlSC3m5Bx_loyjj_srRV6VDEW_-WChNIaRiGZG2UuVKeXqMCyckUO89lAikx6U0pQMafgPwTsMoaEVJp2cG7fTt0jzvwuijb65kJq_ACx77fIhH829_17HA9FOVukZWTfPjj9EepEVMd4x16NWCOgU3pSjBdKdmMTbIJ3vXBZE5FA_e1nYv7q2D__7ifHu_OElOvJlxG1yyW8VMity3h8IHQP1sr6xQBpBmOvnw4AIZappctfg-Yu9X6mCsxJQ7S7c5w1ewwu_U7kUXR6x5926WVvDHCc7O15blUyHS44
Header
------
{
"alg": "RS256",
"typ": "JWT",
"kid": "190"
}
Payload
-------
{
"sub": "https://login.salesforce.com/id/00D20000000nV0aEAE/00520000003hHlDAAU",
"iss": "https://login.salesforce.com",
"at_hash": "-eN-w8-xVsrn0TrJC8tLzw",
"exp": 1406819083,
"iat": 1406818963,
"aud": "3MVG9WtWSKUDG.x6wseHCZId_Nyh5ZQOBejJf4N4NyT_NiRTwallNeR5K0Vxw1bXaIcBL9chokbBXibkSGMYR"
}
Signature
---------
MnFuklB18wjGotkaWPqcUMb0cRT57UfsPCYUUmJVUur5YNFtimQz6l-7iBzKxow1J6nj-7YRyIbwID5TcXFesnP_aMP62rPNFOIZ-nMfYcoG0FnnIxq5s-thfk0jIJSpv_Teb4p1EdBzKfKKb9rxJ4FGP5AlLloJTfqpU17P82TBIBGKPiT8o19DWYUmdn6kUuzM04rSDc2OaCfb4OqodgzpnBXFbXwpUZi15wqZ97NaGBG6turatUguP3wHRcugD8uXqu0aBzqWoUztAxloQiCIS7mPTmO7EYZcUybZUfKUFPygipN_CrgPzGLtUWTQpBoZ-w8xcjTWzrgUBWW1J6o2FN3Dqr7ecgcfxCCSSTFBmDg3wfp9MOb3ztJoN4MFM-IlSC3m5Bx_loyjj_srRV6VDEW_-WChNIaRiGZG2UuVKeXqMCyckUO89lAikx6U0pQMafgPwTsMoaEVJp2cG7fTt0jzvwuijb65kJq_ACx77fIhH829_17HA9FOVukZWTfPjj9EepEVMd4x16NWCOgU3pSjBdKdmMTbIJ3vXBZE5FA_e1nYv7q2D__7ifHu_OElOvJlxG1yyW8VMity3h8IHQP1sr6xQBpBmOvnw4AIZappctfg-Yu9X6mCsxJQ7S7c5w1ewwu_U7kUXR6x5926WVvDHCc7O15blUyHS44
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using Microsoft.IdentityModel.Extensions;
using Microsoft.IdentityModel.Protocols;
namespace MvcApplication1.Controllers
{
public class HomeController : Controller
{
//
// GET: /Home/
public async Task<ActionResult> Index()
{
var manager = new ConfigurationManager<OpenIdConnectConfiguration>("https://emea.salesforce.com/.well-known/openid-configuration", new HttpClient());
var cancelToken = new CancellationTokenSource().Token;
var configuration = await manager.GetConfigurationAsync(cancelToken);
this.Session["configuration"] = configuration;
var uriBuilder = new UriBuilder(configuration.AuthorizationEndpoint);
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
query.Add("client_id", "<redacted>");
query.Add("response_type", "code");
query.Add("scope", "openid");
query.Add("redirect_uri", "https://localhost:44301/oauthcallback");
uriBuilder.Query = query.ToString();
return this.Redirect(uriBuilder.Uri.ToString());
}
public async Task<ActionResult> OauthCallback()
{
var code = this.Request["code"];
var client = new HttpClient();
var content = new FormUrlEncodedContent(new Dictionary<string, string>()
{
{ "grant_type", "authorization_code"},
{ "client_id", "<redacted>"},
{ "client_secret", "<redacted>"},
{ "redirect_uri", "https://localhost:44301/oauthcallback"},
{ "code", code},
});
var configuration = (OpenIdConnectConfiguration)this.Session["configuration"];
var response = await client.PostAsync(configuration.TokenEndpoint, content);
var responseValues = await response.Content.ReadAsAsync<Dictionary<string, string>>();
var converted = responseValues.Select(kvp => new KeyValuePair<string, string[]>(kvp.Key, new string[] { kvp.Value }));
var openidMessage = new OpenIdConnectMessage(converted);
var handlers = SecurityTokenHandlerCollectionExtensions.GetDefaultHandlers();
SecurityToken token = null;
var validationParameters = new TokenValidationParameters
{
IssuerSigningTokens = configuration.SigningTokens
};
// exception thrown here
handlers.ValidateToken(openidMessage.IdToken, validationParameters, out token);
return this.View();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.IdentityModel.Protocol.Extensions" version="1.0.0-RC2" targetFramework="net45" />
<package id="System.IdentityModel.Tokens.Jwt" version="4.0.0-RC2" targetFramework="net45" />
</packages>
using System;
using System.IdentityModel.Tokens;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Extensions;
using Microsoft.IdentityModel.Protocols;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
AsyncMain().Wait();
Console.ReadLine();
}
private static async Task AsyncMain()
{
try
{
var tokenString = File.ReadAllText(@"c:\users\sjefford\desktop\jwt.txt");
var manager = new ConfigurationManager<OpenIdConnectConfiguration>("https://login.salesforce.com/.well-known/openid-configuration", new HttpClient());
var cancelToken = new CancellationTokenSource().Token;
var configuration = await manager.GetConfigurationAsync(cancelToken);
var handlers = SecurityTokenHandlerCollectionExtensions.GetDefaultHandlers();
SecurityToken token = null;
var validationParameters = new TokenValidationParameters
{
IssuerSigningTokens = configuration.SigningTokens
};
handlers.ValidateToken(tokenString, validationParameters, out token);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
}
package main
import (
"crypto"
"crypto/rsa"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
"io/ioutil"
"log"
"math/big"
"net/http"
"strings"
)
func getKey() (*rsa.PublicKey, error) {
log.Println("getkey: getting key from endpoint")
resp, err := http.Get("https://login.salesforce.com/id/keys")
if err != nil {
log.Fatal(err)
return nil, err
}
log.Println("getkey: key fetched")
keyData := make(map[string][]map[string]string)
log.Println("getkey: decoding")
dec := json.NewDecoder(resp.Body)
err = dec.Decode(&keyData)
if err != nil {
log.Fatal(err)
}
keys := keyData["keys"]
for _, keyMap := range keys {
kid := keyMap["kid"]
if kid == "190" {
modBytes, err := decodeSegment(keyMap["n"])
if err != nil {
return nil, err
}
modInt := new(big.Int)
// log.Println(modBytes)
modInt.SetBytes(modBytes)
rsaKey := new(rsa.PublicKey)
rsaKey.N = modInt
rsaKey.E = 65537
log.Println("getkey: got the key")
return rsaKey, nil
}
}
return nil, errors.New("Key not found")
}
type jwtData struct {
payload []byte
signature []byte
}
func (d *jwtData) hashPayload() []byte {
byteArr := sha256.Sum256(d.payload)
return byteArr[:sha256.Size]
}
func decodeSegment(seg string) ([]byte, error) {
if l := len(seg) % 4; l > 0 {
seg += strings.Repeat("=", 4-l)
}
return base64.URLEncoding.DecodeString(seg)
}
func readJwtData(file string) (*jwtData, error) {
bytes, err := ioutil.ReadFile(file)
if err != nil {
return nil, err
}
var j jwtData
str := string(bytes)
parts := strings.Split(str, ".")
j.payload = []byte(parts[0] + "." + parts[1])
j.signature, err = decodeSegment(parts[2])
// log.Println(j.signature)
// log.Println(parts[2])
// log.Println(j.signature)*/
// log.Println(len(j.signature))
return &j, nil
}
func main() {
log.Println("Fetching Key")
key, err := getKey()
if err != nil {
log.Fatal(err)
}
log.Println("Reading JWT")
data, err := readJwtData("jwt.txt")
if err != nil {
log.Fatal(err)
}
log.Println("Hashing payload")
hash := data.hashPayload()
// log.Println(hash)
log.Println("Verifying signature")
err = rsa.VerifyPKCS1v15(key, crypto.SHA256, hash, data.signature)
if err != nil {
log.Fatal(err)
}
log.Println("signature verified")
// c := new(big.Int).SetBytes(data.signature)
// m := encrypt(new(big.Int), key, c)
// k := (key.N.BitLen() + 7) / 8
// em := leftPad(m.Bytes(), k)
// log.Println(hash)
// log.Println(em)
}
func leftPad(input []byte, size int) (out []byte) {
n := len(input)
if n > size {
n = size
}
out = make([]byte, size)
copy(out[len(out)-n:], input)
return
}
func encrypt(c *big.Int, pub *rsa.PublicKey, m *big.Int) *big.Int {
e := big.NewInt(int64(pub.E))
c.Exp(m, e, pub.N)
return c
}
@brentschmaltz
Copy link

We do find the key but the signature does not match.
What algorithm is used to create the signature?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment