vendor: revendor using glide-vc

This commit is contained in:
Eric Chiang
2016-12-07 13:18:03 -08:00
parent a500de802b
commit 89033c2e05
1131 changed files with 2 additions and 249957 deletions

View File

@@ -1 +0,0 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>@

View File

@@ -1 +0,0 @@
<07><04><><EFBFBD><EFBFBD>

View File

@@ -1 +0,0 @@
 015625

View File

@@ -1 +0,0 @@
I

Binary file not shown.

Binary file not shown.

View File

@@ -1 +0,0 @@
<0C> <><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

View File

@@ -1 +0,0 @@
<0C><>

View File

@@ -1 +0,0 @@
<14> <09><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

View File

@@ -1 +0,0 @@
<03><>

View File

@@ -1 +0,0 @@


View File

@@ -1 +0,0 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

Binary file not shown.

View File

@@ -1 +0,0 @@
<06><>Q<EFBFBD><51>

View File

@@ -1 +0,0 @@
<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><0F>

View File

@@ -1 +0,0 @@
<><7F><EFBFBD><EFBFBD><EFBFBD>

View File

@@ -1 +0,0 @@
<15>`<60>H<EFBFBD><48>O <02><><EFBFBD>J<EFBFBD><4A><EFBFBD>c<EFBFBD><63>/

Binary file not shown.

Binary file not shown.

View File

@@ -1 +0,0 @@


View File

@@ -1 +0,0 @@
<01>

Binary file not shown.

View File

@@ -1 +0,0 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1 +0,0 @@


View File

@@ -1 +0,0 @@


Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1 +0,0 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1 +0,0 @@
$

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1 +0,0 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>@

View File

@@ -1 +0,0 @@
+0.E-5

View File

@@ -1 +0,0 @@
-0.E-5

Binary file not shown.

View File

@@ -1 +0,0 @@
<03><>

View File

@@ -1,59 +0,0 @@
# JOSE CLI
The `jose-util` command line utility allows for encryption, decryption, signing
and verification of JOSE messages. Its main purpose is to facilitate dealing
with JOSE messages when testing or debugging.
## Usage
The utility includes the subcommands `encrypt`, `decrypt`, `sign`, `verify` and
`expand`. Examples for each command can be found below.
Algorithms are selected via the `--alg` and `--enc` flags, which influence the
`alg` and `enc` headers in respectively. For JWE, `--alg` specifies the key
managment algorithm (e.g. `RSA-OAEP`) and `--enc` specifies the content
encryption algorithm (e.g. `A128GCM`). For JWS, `--alg` specifies the
signature algorithm (e.g. `PS256`).
Input and output files can be specified via the `--in` and `--out` flags.
Either flag can be omitted, in which case `jose-util` uses stdin/stdout for
input/output respectively. By default each command will output a compact
message, but it's possible to get the full serialization by supplying the
`--full` flag.
Keys are specified via the `--key` flag. Supported key types are naked RSA/EC
keys and X.509 certificates with embedded RSA/EC keys. Keys must be in PEM
or DER formats.
## Examples
### Encrypt
Takes a plaintext as input, encrypts, and prints the encrypted message.
jose-util encrypt -k public-key.pem --alg RSA-OAEP --enc A128GCM
### Decrypt
Takes an encrypted message (JWE) as input, decrypts, and prints the plaintext.
jose-util decrypt -k private-key.pem
### Sign
Takes a payload as input, signs it, and prints the signed message with the embedded payload.
jose-util sign -k private-key.pem --alg PS256
### Verify
Reads a signed message (JWS), verifies it, and extracts the payload.
jose-util verify -k public-key.pem
### Expand
Expands a compact message to the full serialization format.
jose-util expand --format JWE # Expands a compact JWE to full format
jose-util expand --format JWS # Expands a compact JWS to full format

View File

@@ -1,6 +0,0 @@
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDDvoj/bM1HokUjYWO/IDFs26Jo0GIFtU3tMQQu7ZabKscDMK3dZA0mK
v97ij7BBFbCgBwYFK4EEACKhZANiAAT3KhQQCDFN32y/B72g+qOFw/5/aNx1MvZa
rwDDa/2G3V0HLTS0VE82sLEUKS8xwkWFI+gNRXk0vvN+Hf+myJI1jOIY+tYQlh+C
ZiKGNJ6g5/Su7V6ukGtN+UiY+sx+0LI=
-----END EC PRIVATE KEY-----

View File

@@ -1,5 +0,0 @@
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE9yoUEAgxTd9svwe9oPqjhcP+f2jcdTL2
Wq8Aw2v9ht1dBy00tFRPNrCxFCkvMcJFhSPoDUV5NL7zfh3/psiSNYziGPrWEJYf
gmYihjSeoOf0ru1erpBrTflImPrMftCy
-----END PUBLIC KEY-----

View File

@@ -1,94 +0,0 @@
Set up test keys.
$ cat > rsa.pub <<EOF
> -----BEGIN PUBLIC KEY-----
> MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAslWybuiNYR7uOgKuvaBw
> qVk8saEutKhOAaW+3hWF65gJei+ZV8QFfYDxs9ZaRZlWAUMtncQPnw7ZQlXO9ogN
> 5cMcN50C6qMOOZzghK7danalhF5lUETC4Hk3Eisbi/PR3IfVyXaRmqL6X66MKj/J
> AKyD9NFIDVy52K8A198Jojnrw2+XXQW72U68fZtvlyl/BTBWQ9Re5JSTpEcVmpCR
> 8FrFc0RPMBm+G5dRs08vvhZNiTT2JACO5V+J5ZrgP3s5hnGFcQFZgDnXLInDUdoi
> 1MuCjaAU0ta8/08pHMijNix5kFofdPEB954MiZ9k4kQ5/utt02I9x2ssHqw71ojj
> vwIDAQAB
> -----END PUBLIC KEY-----
> EOF
$ cat > rsa.key <<EOF
> -----BEGIN RSA PRIVATE KEY-----
> MIIEogIBAAKCAQEAslWybuiNYR7uOgKuvaBwqVk8saEutKhOAaW+3hWF65gJei+Z
> V8QFfYDxs9ZaRZlWAUMtncQPnw7ZQlXO9ogN5cMcN50C6qMOOZzghK7danalhF5l
> UETC4Hk3Eisbi/PR3IfVyXaRmqL6X66MKj/JAKyD9NFIDVy52K8A198Jojnrw2+X
> XQW72U68fZtvlyl/BTBWQ9Re5JSTpEcVmpCR8FrFc0RPMBm+G5dRs08vvhZNiTT2
> JACO5V+J5ZrgP3s5hnGFcQFZgDnXLInDUdoi1MuCjaAU0ta8/08pHMijNix5kFof
> dPEB954MiZ9k4kQ5/utt02I9x2ssHqw71ojjvwIDAQABAoIBABrYDYDmXom1BzUS
> PE1s/ihvt1QhqA8nmn5i/aUeZkc9XofW7GUqq4zlwPxKEtKRL0IHY7Fw1s0hhhCX
> LA0uE7F3OiMg7lR1cOm5NI6kZ83jyCxxrRx1DUSO2nxQotfhPsDMbaDiyS4WxEts
> 0cp2SYJhdYd/jTH9uDfmt+DGwQN7Jixio1Dj3vwB7krDY+mdre4SFY7Gbk9VxkDg
> LgCLMoq52m+wYufP8CTgpKFpMb2/yJrbLhuJxYZrJ3qd/oYo/91k6v7xlBKEOkwD
> 2veGk9Dqi8YPNxaRktTEjnZb6ybhezat93+VVxq4Oem3wMwou1SfXrSUKtgM/p2H
> vfw/76ECgYEA2fNL9tC8u9M0wjA+kvvtDG96qO6O66Hksssy6RWInD+Iqk3MtHQt
> LeoCjvX+zERqwOb6SI6empk5pZ9E3/9vJ0dBqkxx3nqn4M/nRWnExGgngJsL959t
> f50cdxva8y1RjNhT4kCwTrupX/TP8lAG8SfG1Alo2VFR8iWd8hDQcTECgYEA0Xfj
> EgqAsVh4U0s3lFxKjOepEyp0G1Imty5J16SvcOEAD1Mrmz94aSSp0bYhXNVdbf7n
> Rk77htWC7SE29fGjOzZRS76wxj/SJHF+rktHB2Zt23k1jBeZ4uLMPMnGLY/BJ099
> 5DTGo0yU0rrPbyXosx+ukfQLAHFuggX4RNeM5+8CgYB7M1J/hGMLcUpjcs4MXCgV
> XXbiw2c6v1r9zmtK4odEe42PZ0cNwpY/XAZyNZAAe7Q0stxL44K4NWEmxC80x7lX
> ZKozz96WOpNnO16qGC3IMHAT/JD5Or+04WTT14Ue7UEp8qcIQDTpbJ9DxKk/eglS
> jH+SIHeKULOXw7fSu7p4IQKBgBnyVchIUMSnBtCagpn4DKwDjif3nEY+GNmb/D2g
> ArNiy5UaYk5qwEmV5ws5GkzbiSU07AUDh5ieHgetk5dHhUayZcOSLWeBRFCLVnvU
> i0nZYEZNb1qZGdDG8zGcdNXz9qMd76Qy/WAA/nZT+Zn1AiweAovFxQ8a/etRPf2Z
> DbU1AoGAHpCgP7B/4GTBe49H0AQueQHBn4RIkgqMy9xiMeR+U+U0vaY0TlfLhnX+
> 5PkNfkPXohXlfL7pxwZNYa6FZhCAubzvhKCdUASivkoGaIEk6g1VTVYS/eDVQ4CA
> slfl+elXtLq/l1kQ8C14jlHrQzSXx4PQvjDEnAmaHSJNz4mP9Fg=
> -----END RSA PRIVATE KEY-----
> EOF
$ cat > ec.pub <<EOF
> -----BEGIN PUBLIC KEY-----
> MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE9yoUEAgxTd9svwe9oPqjhcP+f2jcdTL2
> Wq8Aw2v9ht1dBy00tFRPNrCxFCkvMcJFhSPoDUV5NL7zfh3/psiSNYziGPrWEJYf
> gmYihjSeoOf0ru1erpBrTflImPrMftCy
> -----END PUBLIC KEY-----
> EOF
$ cat > ec.key <<EOF
> -----BEGIN EC PRIVATE KEY-----
> MIGkAgEBBDDvoj/bM1HokUjYWO/IDFs26Jo0GIFtU3tMQQu7ZabKscDMK3dZA0mK
> v97ij7BBFbCgBwYFK4EEACKhZANiAAT3KhQQCDFN32y/B72g+qOFw/5/aNx1MvZa
> rwDDa/2G3V0HLTS0VE82sLEUKS8xwkWFI+gNRXk0vvN+Hf+myJI1jOIY+tYQlh+C
> ZiKGNJ6g5/Su7V6ukGtN+UiY+sx+0LI=
> -----END EC PRIVATE KEY-----
> EOF
Encrypt and then decrypt a test message (RSA).
$ echo "Lorem ipsum dolor sit amet" |
> jose-util encrypt --alg RSA-OAEP --enc A128GCM --key rsa.pub |
> jose-util decrypt --key rsa.key
Lorem ipsum dolor sit amet
Encrypt and then decrypt a test message (EC).
$ echo "Lorem ipsum dolor sit amet" |
> jose-util encrypt --alg ECDH-ES+A128KW --enc A128GCM --key ec.pub |
> jose-util decrypt --key ec.key
Lorem ipsum dolor sit amet
Sign and verify a test message (RSA).
$ echo "Lorem ipsum dolor sit amet" |
> jose-util sign --alg PS256 --key rsa.key |
> jose-util verify --key rsa.pub
Lorem ipsum dolor sit amet
Sign and verify a test message (EC).
$ echo "Lorem ipsum dolor sit amet" |
> jose-util sign --alg ES384 --key ec.key |
> jose-util verify --key ec.pub
Lorem ipsum dolor sit amet
Expand a compact message to full format.
$ echo "eyJhbGciOiJFUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQK.QPU35XY913Im7ZEaN2yHykfbtPqjHZvYp-lV8OcTAJZs67bJFSdTSkQhQWE9ch6tvYrj_7py6HKaWVFLll_s_Rm6bmwq3JszsHrIvFFm1NydruYHhvAnx7rjYiqwOu0W" |
> jose-util expand --format JWS
{"payload":"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQK","protected":"eyJhbGciOiJFUzM4NCJ9","signature":"QPU35XY913Im7ZEaN2yHykfbtPqjHZvYp-lV8OcTAJZs67bJFSdTSkQhQWE9ch6tvYrj_7py6HKaWVFLll_s_Rm6bmwq3JszsHrIvFFm1NydruYHhvAnx7rjYiqwOu0W"}

View File

@@ -1,189 +0,0 @@
/*-
* Copyright 2014 Square 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 main
import (
"fmt"
"io/ioutil"
"os"
"gopkg.in/alecthomas/kingpin.v2"
"gopkg.in/square/go-jose.v2"
)
var (
app = kingpin.New("jose-util", "A command-line utility for dealing with JOSE objects.")
keyFile = app.Flag("key", "Path to key file (PEM or DER-encoded)").ExistingFile()
inFile = app.Flag("in", "Path to input file (stdin if missing)").ExistingFile()
outFile = app.Flag("out", "Path to output file (stdout if missing)").ExistingFile()
encryptCommand = app.Command("encrypt", "Encrypt a plaintext, output ciphertext.")
algFlag = encryptCommand.Flag("alg", "Key management algorithm (e.g. RSA-OAEP)").Required().String()
encFlag = encryptCommand.Flag("enc", "Content encryption algorithm (e.g. A128GCM)").Required().String()
decryptCommand = app.Command("decrypt", "Decrypt a ciphertext, output plaintext.")
signCommand = app.Command("sign", "Sign a payload, output signed message.")
sigAlgFlag = signCommand.Flag("alg", "Key management algorithm (e.g. RSA-OAEP)").Required().String()
verifyCommand = app.Command("verify", "Verify a signed message, output payload.")
expandCommand = app.Command("expand", "Expand JOSE object to full serialization format.")
formatFlag = expandCommand.Flag("format", "Type of message to expand (JWS or JWE, defaults to JWE)").String()
full = app.Flag("full", "Use full serialization format (instead of compact)").Bool()
)
func main() {
app.Version("v2")
command := kingpin.MustParse(app.Parse(os.Args[1:]))
var keyBytes []byte
var err error
if command != "expand" {
keyBytes, err = ioutil.ReadFile(*keyFile)
exitOnError(err, "unable to read key file")
}
switch command {
case "encrypt":
pub, err := LoadPublicKey(keyBytes)
exitOnError(err, "unable to read public key")
alg := jose.KeyAlgorithm(*algFlag)
enc := jose.ContentEncryption(*encFlag)
crypter, err := jose.NewEncrypter(enc, jose.Recipient{Algorithm: alg, Key: pub}, nil)
exitOnError(err, "unable to instantiate encrypter")
obj, err := crypter.Encrypt(readInput(*inFile))
exitOnError(err, "unable to encrypt")
var msg string
if *full {
msg = obj.FullSerialize()
} else {
msg, err = obj.CompactSerialize()
exitOnError(err, "unable to serialize message")
}
writeOutput(*outFile, []byte(msg))
case "decrypt":
priv, err := LoadPrivateKey(keyBytes)
exitOnError(err, "unable to read private key")
obj, err := jose.ParseEncrypted(string(readInput(*inFile)))
exitOnError(err, "unable to parse message")
plaintext, err := obj.Decrypt(priv)
exitOnError(err, "unable to decrypt message")
writeOutput(*outFile, plaintext)
case "sign":
signingKey, err := LoadPrivateKey(keyBytes)
exitOnError(err, "unable to read private key")
alg := jose.SignatureAlgorithm(*sigAlgFlag)
signer, err := jose.NewSigner(jose.SigningKey{Algorithm: alg, Key: signingKey}, nil)
exitOnError(err, "unable to make signer")
obj, err := signer.Sign(readInput(*inFile))
exitOnError(err, "unable to sign")
var msg string
if *full {
msg = obj.FullSerialize()
} else {
msg, err = obj.CompactSerialize()
exitOnError(err, "unable to serialize message")
}
writeOutput(*outFile, []byte(msg))
case "verify":
verificationKey, err := LoadPublicKey(keyBytes)
exitOnError(err, "unable to read private key")
obj, err := jose.ParseSigned(string(readInput(*inFile)))
exitOnError(err, "unable to parse message")
plaintext, err := obj.Verify(verificationKey)
exitOnError(err, "invalid signature")
writeOutput(*outFile, plaintext)
case "expand":
input := string(readInput(*inFile))
var serialized string
var err error
switch *formatFlag {
case "", "JWE":
var jwe *jose.JSONWebEncryption
jwe, err = jose.ParseEncrypted(input)
if err == nil {
serialized = jwe.FullSerialize()
}
case "JWS":
var jws *jose.JSONWebSignature
jws, err = jose.ParseSigned(input)
if err == nil {
serialized = jws.FullSerialize()
}
}
exitOnError(err, "unable to expand message")
writeOutput(*outFile, []byte(serialized))
writeOutput(*outFile, []byte("\n"))
}
}
// Exit and print error message if we encountered a problem
func exitOnError(err error, msg string) {
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %s\n", msg, err)
os.Exit(1)
}
}
// Read input from file or stdin
func readInput(path string) []byte {
var bytes []byte
var err error
if path != "" {
bytes, err = ioutil.ReadFile(path)
} else {
bytes, err = ioutil.ReadAll(os.Stdin)
}
exitOnError(err, "unable to read input")
return bytes
}
// Write output to file or stdin
func writeOutput(path string, data []byte) {
var err error
if path != "" {
err = ioutil.WriteFile(path, data, 0644)
} else {
_, err = os.Stdout.Write(data)
}
exitOnError(err, "unable to write output")
}

View File

@@ -1,6 +0,0 @@
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDDvoj/bM1HokUjYWO/IDFs26Jo0GIFtU3tMQQu7ZabKscDMK3dZA0mK
v97ij7BBFbCgBwYFK4EEACKhZANiAAT3KhQQCDFN32y/B72g+qOFw/5/aNx1MvZa
rwDDa/2G3V0HLTS0VE82sLEUKS8xwkWFI+gNRXk0vvN+Hf+myJI1jOIY+tYQlh+C
ZiKGNJ6g5/Su7V6ukGtN+UiY+sx+0LI=
-----END EC PRIVATE KEY-----

View File

@@ -1,5 +0,0 @@
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE9yoUEAgxTd9svwe9oPqjhcP+f2jcdTL2
Wq8Aw2v9ht1dBy00tFRPNrCxFCkvMcJFhSPoDUV5NL7zfh3/psiSNYziGPrWEJYf
gmYihjSeoOf0ru1erpBrTflImPrMftCy
-----END PUBLIC KEY-----

View File

@@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAslWybuiNYR7uOgKuvaBwqVk8saEutKhOAaW+3hWF65gJei+Z
V8QFfYDxs9ZaRZlWAUMtncQPnw7ZQlXO9ogN5cMcN50C6qMOOZzghK7danalhF5l
UETC4Hk3Eisbi/PR3IfVyXaRmqL6X66MKj/JAKyD9NFIDVy52K8A198Jojnrw2+X
XQW72U68fZtvlyl/BTBWQ9Re5JSTpEcVmpCR8FrFc0RPMBm+G5dRs08vvhZNiTT2
JACO5V+J5ZrgP3s5hnGFcQFZgDnXLInDUdoi1MuCjaAU0ta8/08pHMijNix5kFof
dPEB954MiZ9k4kQ5/utt02I9x2ssHqw71ojjvwIDAQABAoIBABrYDYDmXom1BzUS
PE1s/ihvt1QhqA8nmn5i/aUeZkc9XofW7GUqq4zlwPxKEtKRL0IHY7Fw1s0hhhCX
LA0uE7F3OiMg7lR1cOm5NI6kZ83jyCxxrRx1DUSO2nxQotfhPsDMbaDiyS4WxEts
0cp2SYJhdYd/jTH9uDfmt+DGwQN7Jixio1Dj3vwB7krDY+mdre4SFY7Gbk9VxkDg
LgCLMoq52m+wYufP8CTgpKFpMb2/yJrbLhuJxYZrJ3qd/oYo/91k6v7xlBKEOkwD
2veGk9Dqi8YPNxaRktTEjnZb6ybhezat93+VVxq4Oem3wMwou1SfXrSUKtgM/p2H
vfw/76ECgYEA2fNL9tC8u9M0wjA+kvvtDG96qO6O66Hksssy6RWInD+Iqk3MtHQt
LeoCjvX+zERqwOb6SI6empk5pZ9E3/9vJ0dBqkxx3nqn4M/nRWnExGgngJsL959t
f50cdxva8y1RjNhT4kCwTrupX/TP8lAG8SfG1Alo2VFR8iWd8hDQcTECgYEA0Xfj
EgqAsVh4U0s3lFxKjOepEyp0G1Imty5J16SvcOEAD1Mrmz94aSSp0bYhXNVdbf7n
Rk77htWC7SE29fGjOzZRS76wxj/SJHF+rktHB2Zt23k1jBeZ4uLMPMnGLY/BJ099
5DTGo0yU0rrPbyXosx+ukfQLAHFuggX4RNeM5+8CgYB7M1J/hGMLcUpjcs4MXCgV
XXbiw2c6v1r9zmtK4odEe42PZ0cNwpY/XAZyNZAAe7Q0stxL44K4NWEmxC80x7lX
ZKozz96WOpNnO16qGC3IMHAT/JD5Or+04WTT14Ue7UEp8qcIQDTpbJ9DxKk/eglS
jH+SIHeKULOXw7fSu7p4IQKBgBnyVchIUMSnBtCagpn4DKwDjif3nEY+GNmb/D2g
ArNiy5UaYk5qwEmV5ws5GkzbiSU07AUDh5ieHgetk5dHhUayZcOSLWeBRFCLVnvU
i0nZYEZNb1qZGdDG8zGcdNXz9qMd76Qy/WAA/nZT+Zn1AiweAovFxQ8a/etRPf2Z
DbU1AoGAHpCgP7B/4GTBe49H0AQueQHBn4RIkgqMy9xiMeR+U+U0vaY0TlfLhnX+
5PkNfkPXohXlfL7pxwZNYa6FZhCAubzvhKCdUASivkoGaIEk6g1VTVYS/eDVQ4CA
slfl+elXtLq/l1kQ8C14jlHrQzSXx4PQvjDEnAmaHSJNz4mP9Fg=
-----END RSA PRIVATE KEY-----

View File

@@ -1,9 +0,0 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAslWybuiNYR7uOgKuvaBw
qVk8saEutKhOAaW+3hWF65gJei+ZV8QFfYDxs9ZaRZlWAUMtncQPnw7ZQlXO9ogN
5cMcN50C6qMOOZzghK7danalhF5lUETC4Hk3Eisbi/PR3IfVyXaRmqL6X66MKj/J
AKyD9NFIDVy52K8A198Jojnrw2+XXQW72U68fZtvlyl/BTBWQ9Re5JSTpEcVmpCR
8FrFc0RPMBm+G5dRs08vvhZNiTT2JACO5V+J5ZrgP3s5hnGFcQFZgDnXLInDUdoi
1MuCjaAU0ta8/08pHMijNix5kFofdPEB954MiZ9k4kQ5/utt02I9x2ssHqw71ojj
vwIDAQAB
-----END PUBLIC KEY-----

View File

@@ -1,74 +0,0 @@
/*-
* Copyright 2014 Square 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 main
import (
"crypto/x509"
"encoding/pem"
"fmt"
)
// LoadPublicKey loads a public key from PEM/DER-encoded data.
func LoadPublicKey(data []byte) (interface{}, error) {
input := data
block, _ := pem.Decode(data)
if block != nil {
input = block.Bytes
}
// Try to load SubjectPublicKeyInfo
pub, err0 := x509.ParsePKIXPublicKey(input)
if err0 == nil {
return pub, nil
}
cert, err1 := x509.ParseCertificate(input)
if err1 == nil {
return cert.PublicKey, nil
}
return nil, fmt.Errorf("square/go-jose: parse error, got '%s' and '%s'", err0, err1)
}
// LoadPrivateKey loads a private key from PEM/DER-encoded data.
func LoadPrivateKey(data []byte) (interface{}, error) {
input := data
block, _ := pem.Decode(data)
if block != nil {
input = block.Bytes
}
var priv interface{}
priv, err0 := x509.ParsePKCS1PrivateKey(input)
if err0 == nil {
return priv, nil
}
priv, err1 := x509.ParsePKCS8PrivateKey(input)
if err1 == nil {
return priv, nil
}
priv, err2 := x509.ParseECPrivateKey(input)
if err2 == nil {
return priv, nil
}
return nil, fmt.Errorf("square/go-jose: parse error, got '%s', '%s' and '%s'", err0, err1, err2)
}

Binary file not shown.

View File

@@ -1,227 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 Square, 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 jwt
import (
"reflect"
"gopkg.in/square/go-jose.v2/json"
"gopkg.in/square/go-jose.v2"
)
// Builder is a utility for making JSON Web Tokens. Calls can be chained, and
// errors are accumulated until the final call to CompactSerialize/FullSerialize.
type Builder interface {
// Claims encodes claims into JWE/JWS form. Multiple calls will merge claims
// into single JSON object.
Claims(i interface{}) Builder
// Token builds a JSONWebToken from provided data.
Token() (*JSONWebToken, error)
// FullSerialize serializes a token using the full serialization format.
FullSerialize() (string, error)
// CompactSerialize serializes a token using the compact serialization format.
CompactSerialize() (string, error)
}
type builder struct {
payload map[string]interface{}
err error
}
type signedBuilder struct {
builder
sig jose.Signer
}
type encryptedBuilder struct {
builder
enc jose.Encrypter
}
// Signed creates builder for signed tokens.
func Signed(sig jose.Signer) Builder {
return &signedBuilder{
sig: sig,
}
}
// Encrypted creates builder for encrypted tokens.
func Encrypted(enc jose.Encrypter) Builder {
return &encryptedBuilder{
enc: enc,
}
}
func (b builder) claims(i interface{}) builder {
if b.err != nil {
return b
}
m, ok := i.(map[string]interface{})
switch {
case ok:
return b.merge(m)
case reflect.Indirect(reflect.ValueOf(i)).Kind() == reflect.Struct:
m, err := normalize(i)
if err != nil {
return builder{
err: err,
}
}
return b.merge(m)
default:
return builder{
err: ErrInvalidClaims,
}
}
}
func normalize(i interface{}) (map[string]interface{}, error) {
m := make(map[string]interface{})
raw, err := json.Marshal(i)
if err != nil {
return nil, err
}
if err := json.Unmarshal(raw, &m); err != nil {
return nil, err
}
return m, nil
}
func (b *builder) merge(m map[string]interface{}) builder {
p := make(map[string]interface{})
for k, v := range b.payload {
p[k] = v
}
for k, v := range m {
p[k] = v
}
return builder{
payload: p,
}
}
func (b *builder) token(p func(interface{}) ([]byte, error), h []jose.Header) (*JSONWebToken, error) {
return &JSONWebToken{
payload: p,
Headers: h,
}, nil
}
func (b *signedBuilder) Claims(i interface{}) Builder {
return &signedBuilder{
builder: b.builder.claims(i),
sig: b.sig,
}
}
func (b *signedBuilder) Token() (*JSONWebToken, error) {
sig, err := b.sign()
if err != nil {
return nil, err
}
h := make([]jose.Header, len(sig.Signatures))
for i, v := range sig.Signatures {
h[i] = v.Header
}
return b.builder.token(sig.Verify, h)
}
func (b *signedBuilder) CompactSerialize() (string, error) {
sig, err := b.sign()
if err != nil {
return "", err
}
return sig.CompactSerialize()
}
func (b *signedBuilder) FullSerialize() (string, error) {
sig, err := b.sign()
if err != nil {
return "", err
}
return sig.FullSerialize(), nil
}
func (b *signedBuilder) sign() (*jose.JSONWebSignature, error) {
if b.err != nil {
return nil, b.err
}
p, err := json.Marshal(b.payload)
if err != nil {
return nil, err
}
return b.sig.Sign(p)
}
func (b *encryptedBuilder) Claims(i interface{}) Builder {
return &encryptedBuilder{
builder: b.builder.claims(i),
enc: b.enc,
}
}
func (b *encryptedBuilder) CompactSerialize() (string, error) {
enc, err := b.encrypt()
if err != nil {
return "", err
}
return enc.CompactSerialize()
}
func (b *encryptedBuilder) FullSerialize() (string, error) {
enc, err := b.encrypt()
if err != nil {
return "", err
}
return enc.FullSerialize(), nil
}
func (b *encryptedBuilder) Token() (*JSONWebToken, error) {
enc, err := b.encrypt()
if err != nil {
return nil, err
}
return b.builder.token(enc.Decrypt, []jose.Header{enc.Header})
}
func (b *encryptedBuilder) encrypt() (*jose.JSONWebEncryption, error) {
if b.err != nil {
return nil, b.err
}
p, err := json.Marshal(b.payload)
if err != nil {
return nil, err
}
return b.enc.Encrypt(p)
}

View File

@@ -1,415 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 Square, 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 jwt
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"errors"
"io"
"reflect"
"sort"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/square/go-jose.v2"
)
type testClaims struct {
Subject string `json:"sub"`
}
type invalidMarshalClaims struct {
}
var errInvalidMarshalClaims = errors.New("Failed marshaling invalid claims.")
func (c invalidMarshalClaims) MarshalJSON() ([]byte, error) {
return nil, errInvalidMarshalClaims
}
var sampleClaims = Claims{
Subject: "42",
IssuedAt: NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
Issuer: "issuer",
Audience: Audience{"a1", "a2"},
}
func TestBuilderCustomClaimsNonPointer(t *testing.T) {
jwt, err := Signed(rsaSigner).Claims(testClaims{"foo"}).CompactSerialize()
require.NoError(t, err, "Error creating JWT.")
parsed, err := ParseSigned(jwt)
require.NoError(t, err, "Error parsing JWT.")
out := &testClaims{}
if assert.NoError(t, parsed.Claims(&testPrivRSAKey1.PublicKey, out), "Error unmarshaling claims.") {
assert.Equal(t, "foo", out.Subject)
}
}
func TestBuilderCustomClaimsPointer(t *testing.T) {
jwt, err := Signed(rsaSigner).Claims(&testClaims{"foo"}).CompactSerialize()
require.NoError(t, err, "Error creating JWT.")
parsed, err := ParseSigned(jwt)
require.NoError(t, err, "Error parsing JWT.")
out := &testClaims{}
if assert.NoError(t, parsed.Claims(&testPrivRSAKey1.PublicKey, out), "Error unmarshaling claims.") {
assert.Equal(t, "foo", out.Subject)
}
}
func TestBuilderMergeClaims(t *testing.T) {
jwt, err := Signed(rsaSigner).
Claims(&Claims{
Subject: "42",
}).
Claims(map[string]interface{}{
"Scopes": []string{"read:users"},
}).
CompactSerialize()
require.NoError(t, err, "Error creating JWT.")
parsed, err := ParseSigned(jwt)
require.NoError(t, err, "Error parsing JWT.")
out := make(map[string]interface{})
if assert.NoError(t, parsed.Claims(&testPrivRSAKey1.PublicKey, &out), "Error unmarshaling claims.") {
assert.Equal(t, map[string]interface{}{
"sub": "42",
"Scopes": []interface{}{"read:users"},
}, out)
}
_, err = Signed(rsaSigner).Claims("invalid-claims").Claims(&testClaims{"foo"}).CompactSerialize()
assert.Equal(t, err, ErrInvalidClaims)
_, err = Signed(rsaSigner).Claims(&invalidMarshalClaims{}).CompactSerialize()
assert.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
}
func TestSignedFullSerializeAndToken(t *testing.T) {
b := Signed(rsaSigner).Claims(&testClaims{"foo"})
jwt, err := b.FullSerialize()
require.NoError(t, err, "Error creating JWT.")
parsed, err := ParseSigned(jwt)
require.NoError(t, err, "Error parsing JWT.")
out := &testClaims{}
if assert.NoError(t, parsed.Claims(&testPrivRSAKey1.PublicKey, &out), "Error unmarshaling claims.") {
assert.Equal(t, &testClaims{
Subject: "foo",
}, out)
}
jwt2, err := b.Token()
require.NoError(t, err, "Error creating JWT.")
out2 := &testClaims{}
if assert.NoError(t, jwt2.Claims(&testPrivRSAKey1.PublicKey, &out2), "Error unmarshaling claims.") {
assert.Equal(t, &testClaims{
Subject: "foo",
}, out2)
}
b2 := Signed(rsaSigner).Claims(&invalidMarshalClaims{})
_, err = b2.FullSerialize()
require.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
_, err = b2.Token()
require.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
}
func TestEncryptedFullSerializeAndToken(t *testing.T) {
recipient := jose.Recipient{
Algorithm: jose.RSA1_5,
Key: testPrivRSAKey1.Public(),
}
encrypter, err := jose.NewEncrypter(jose.A128CBC_HS256, recipient, nil)
require.NoError(t, err, "Error creating encrypter.")
b := Encrypted(encrypter).Claims(&testClaims{"foo"})
jwt, err := b.FullSerialize()
require.NoError(t, err, "Error creating JWT.")
parsed, err := ParseEncrypted(jwt)
require.NoError(t, err, "Error parsing JWT.")
out := &testClaims{}
if assert.NoError(t, parsed.Claims(testPrivRSAKey1, &out)) {
assert.Equal(t, &testClaims{
Subject: "foo",
}, out)
}
jwt2, err := b.Token()
require.NoError(t, err, "Error creating JWT.")
out2 := &testClaims{}
if assert.NoError(t, jwt2.Claims(testPrivRSAKey1, &out2)) {
assert.Equal(t, &testClaims{
Subject: "foo",
}, out2)
}
b2 := Encrypted(encrypter).Claims(&invalidMarshalClaims{})
_, err = b2.FullSerialize()
require.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
_, err = b2.Token()
require.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
}
func TestBuilderHeadersSigner(t *testing.T) {
tests := []struct {
Keys []*rsa.PrivateKey
Claims interface{}
}{
{
Keys: []*rsa.PrivateKey{testPrivRSAKey1},
Claims: &Claims{Issuer: "foo"},
},
{
Keys: []*rsa.PrivateKey{testPrivRSAKey1, testPrivRSAKey2},
Claims: &Claims{Issuer: "foo"},
},
}
for i, tc := range tests {
wantKeyIDs := make([]string, len(tc.Keys))
signingKeys := make([]jose.SigningKey, len(tc.Keys))
for j, key := range tc.Keys {
keyIDBytes := make([]byte, 20)
if _, err := io.ReadFull(rand.Reader, keyIDBytes); err != nil {
t.Fatalf("failed to read random bytes: %v", err)
}
keyID := hex.EncodeToString(keyIDBytes)
wantKeyIDs[j] = keyID
signingKeys[j] = jose.SigningKey{
Algorithm: jose.RS256,
Key: &jose.JSONWebKey{
KeyID: keyID,
Algorithm: "RSA",
Key: key,
},
}
}
signer, err := jose.NewMultiSigner(signingKeys, nil)
if err != nil {
t.Errorf("case %d: NewMultiSigner(): %v", i, err)
continue
}
var token string
if len(tc.Keys) == 1 {
token, err = Signed(signer).Claims(tc.Claims).CompactSerialize()
} else {
token, err = Signed(signer).Claims(tc.Claims).FullSerialize()
}
if err != nil {
t.Errorf("case %d: failed to create token: %v", i, err)
continue
}
jws, err := jose.ParseSigned(token)
if err != nil {
t.Errorf("case %d: parse signed: %v", i, err)
continue
}
gotKeyIDs := make([]string, len(jws.Signatures))
for i, sig := range jws.Signatures {
gotKeyIDs[i] = sig.Header.KeyID
}
sort.Strings(wantKeyIDs)
sort.Strings(gotKeyIDs)
if !reflect.DeepEqual(wantKeyIDs, gotKeyIDs) {
t.Errorf("case %d: wanted=%q got=%q", i, wantKeyIDs, gotKeyIDs)
}
}
}
func TestBuilderHeadersEncrypter(t *testing.T) {
key := testPrivRSAKey1
claims := &Claims{Issuer: "foo"}
keyIDBytes := make([]byte, 20)
if _, err := io.ReadFull(rand.Reader, keyIDBytes); err != nil {
t.Fatalf("failed to read random bytes: %v", err)
}
keyID := hex.EncodeToString(keyIDBytes)
wantKeyID := keyID
recipient := jose.Recipient{
Algorithm: jose.RSA1_5,
Key: key.Public(),
KeyID: keyID,
}
encrypter, err := jose.NewEncrypter(jose.A128CBC_HS256, recipient, nil)
if err != nil {
t.Errorf("NewEncrypter(): %v", err)
return
}
token, err := Encrypted(encrypter).Claims(claims).CompactSerialize()
if err != nil {
t.Errorf("failed to create token: %v", err)
return
}
jwe, err := jose.ParseEncrypted(token)
if err != nil {
t.Errorf("parse signed: %v", err)
return
}
if gotKeyID := jwe.Header.KeyID; gotKeyID != wantKeyID {
t.Errorf("wanted=%q got=%q", wantKeyID, gotKeyID)
}
}
func BenchmarkMapClaims(b *testing.B) {
m := map[string]interface{}{
"sub": "42",
"iat": 1451606400,
"iss": "issuer",
"aud": []string{"a1", "a2"},
}
for i := 0; i < b.N; i++ {
Signed(rsaSigner).Claims(m)
}
}
func BenchmarkStructClaims(b *testing.B) {
for i := 0; i < b.N; i++ {
Signed(rsaSigner).Claims(sampleClaims)
}
}
func BenchmarkSignedCompactSerializeRSA(b *testing.B) {
tb := Signed(rsaSigner).Claims(sampleClaims)
b.ResetTimer()
for i := 0; i < b.N; i++ {
tb.CompactSerialize()
}
}
func BenchmarkSignedCompactSerializeSHA(b *testing.B) {
tb := Signed(hmacSigner).Claims(sampleClaims)
b.ResetTimer()
for i := 0; i < b.N; i++ {
tb.CompactSerialize()
}
}
func mustUnmarshalRSA(data string) *rsa.PrivateKey {
block, _ := pem.Decode([]byte(data))
if block == nil {
panic("failed to decode PEM data")
}
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
panic("failed to parse RSA key: " + err.Error())
}
if key, ok := key.(*rsa.PrivateKey); ok {
return key
}
panic("key is not of type *rsa.PrivateKey")
}
func mustMakeSigner(alg jose.SignatureAlgorithm, k interface{}) jose.Signer {
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: alg, Key: k}, nil)
if err != nil {
panic("failed to create signer:" + err.Error())
}
return sig
}
var (
sharedKey = []byte("secret")
sharedEncryptionKey = []byte("itsa16bytesecret")
testPrivRSAKey1 = mustUnmarshalRSA(`-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDIHBvDHAr7jh8h
xaqBCl11fjI9YZtdC5b3HtXTXZW3c2dIOImNUjffT8POP6p5OpzivmC1om7iOyuZ
3nJjC9LT3zqqs3f2i5d4mImxEuqG6uWdryFfkp0uIv5VkjVO+iQWd6pDAPGP7r1Z
foXCleyCtmyNH4JSkJneNPOk/4BxO8vcvRnCMT/Gv81IT6H+OQ6OovWOuJr8RX9t
1wuCjC9ezZxeI9ONffhiO5FMrVh5H9LJTl3dPOVa4aEcOvgd45hBmvxAyXqf8daE
6Kl2O7vQ4uwgnSTVXYIIjCjbepuersApIMGx/XPSgiU1K3Xtah/TBvep+S3VlwPc
q/QH25S9AgMBAAECggEAe+y8XKYfPw4SxY1uPB+5JSwT3ON3nbWxtjSIYy9Pqp5z
Vcx9kuFZ7JevQSk4X38m7VzM8282kC/ono+d8yy9Uayq3k/qeOqV0X9Vti1qxEbw
ECkG1/MqGApfy4qSLOjINInDDV+mOWa2KJgsKgdCwuhKbVMYGB2ozG2qfYIlfvlY
vLcBEpGWmswJHNmkcjTtGFIyJgPbsI6ndkkOeQbqQKAaadXtG1xUzH+vIvqaUl/l
AkNf+p4qhPkHsoAWXf1qu9cYa2T8T+mEo79AwlgVC6awXQWNRTiyClDJC7cu6NBy
ZHXCLFMbalzWF9qeI2OPaFX2x3IBWrbyDxcJ4TSdQQKBgQD/Fp/uQonMBh1h4Vi4
HlxZdqSOArTitXValdLFGVJ23MngTGV/St4WH6eRp4ICfPyldsfcv6MZpNwNm1Rn
lB5Gtpqpby1dsrOSfvVbY7U3vpLnd8+hJ/lT5zCYt5Eor46N6iWRkYWzNe4PixiF
z1puGUvFCbZdeeACVrPLmW3JKQKBgQDI0y9WTf8ezKPbtap4UEE6yBf49ftohVGz
p4iD6Ng1uqePwKahwoVXKOc179CjGGtW/UUBORAoKRmxdHajHq6LJgsBxpaARz21
COPy99BUyp9ER5P8vYn63lC7Cpd/K7uyMjaz1DAzYBZIeVZHIw8O9wuGNJKjRFy9
SZyD3V0ddQKBgFMdohrWH2QVEfnUnT3Q1rJn0BJdm2bLTWOosbZ7G72TD0xAWEnz
sQ1wXv88n0YER6X6YADziEdQykq8s/HT91F/KkHO8e83zP8M0xFmGaQCOoelKEgQ
aFMIX3NDTM7+9OoUwwz9Z50PE3SJFAJ1n7eEEoYvNfabQXxBl+/dHEKRAoGAPEvU
EaiXacrtg8EWrssB2sFLGU/ZrTciIbuybFCT4gXp22pvXXAHEvVP/kzDqsRhLhwb
BNP6OuSkNziNikpjA5pngZ/7fgZly54gusmW/m5bxWdsUl0iOXVYbeAvPlqGH2me
LP4Pfs1hw17S/cbT9Z1NE31jbavP4HFikeD73SUCgYEArQfuudml6ei7XZ1Emjq8
jZiD+fX6e6BD/ISatVnuyZmGj9wPFsEhY2BpLiAMQHMDIvH9nlKzsFvjkTPB86qG
jCh3D67Os8eSBk5uRC6iW3Fc4DXvB5EFS0W9/15Sl+V5vXAcrNMpYS82OTSMG2Gt
b9Ym/nxaqyTu0PxajXkKm5Q=
-----END PRIVATE KEY-----`)
testPrivRSAKey2 = mustUnmarshalRSA(`-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxJ09jkXZ5Okyq
FrEKrs+GTzZRvoLziyzDTIZLJC6BVryau4gaFjuBG+pnm4z53oDP0XVnjFsx1mBw
R6RHeXlXbxLXsMfJpMzU9I2SRen9DokpD187CAnjLOoN9QRl1h8CA+sqR5Jw9mdl
mdaBKC99M9QYAPK3vGNfPC4soo8LDSBiemmt5raL4WSfoYh/6qg5rHUTymY28uxV
ew3I9Yp+3ltIw+WlRDtW5l+MM5CSUofjj2zcgcG3LEuPtvyZ+CSObxxcZZugm9zc
JdiazNyUxtX8yAj3Xg8Hde0jt0QDXv7A+U0KMVi9lX6PJEaNj4tOhOmQhJVMzAyr
1W/bifZVAgMBAAECggEAduKnn21GMZLTUi4KP94SvNK55F/Sp7hVoPbhBNpSL1BT
IBAMBV24LyvZwhAcqq8MiOrLPGNv6+EvNQqPD7xQl0GeRouHeCYVpDA+NdSfc8jm
eVysjwQVBpTkudsdSW5JvuN8VRJVD2P8/a0gy+p4/C/k/Prd6DoQAiBz6FZrYoEd
iYgIegHOMXWd4vzO3ENOWSIUI6ci7Aro+Y0Z75kfiVokAGhUcFgrZ58E82fBYh8I
cxO20oMnucGrLicQzj536jx4wX3Cdd4jr9UVEJ9ZII1ldlp03nZlFLXqJH1547Aq
ZM+3vVcBGoJ8T9ZQ4VDAL++0K2DLC9JkTARAYCEi/QKBgQDebIc1+2zblhQtVQ/e
IbEErZcB7v+TkUoRoBfR0lj7bKBFJgRe37fgu1xf95/s63okdnOw/OuQqtGmgx/J
TL3yULBdNcwTCRm41t+cqoGymjK0VRbqk6CWBId0E3r5TaCVWedk2JI2XwTvIJ1A
eDiqfJeDHUD44yaonwbysj9ZDwKBgQDL5VQfTppVaJk2PXNwhAkRQklZ8RFmt/7p
yA3dddQNdwMk4Fl8F7QuO1gBxDiHdnwIrlEOz6fTsM3LwIS+Q12P1vYFIhpo7HDB
wvjfMwCPxBIS4jI28RgcAf0VbZ/+CHAm6bb9iDwsjXhh1J5oOm5VKnju6/rPH/QY
+md40pnSWwKBgBnKPbdNquafNUG4XjmkcHEZa6wGuU20CAGZLYnfuP+WLdM2wET7
7cc6ElDyVnHTL/twXKPF/85rcBm9lH7zzgZ9wqVcKoh+gqQDDjSNNLKv3Hc6cojK
i1E5vzb/Vz/290q5/PGdhv6U7+6GOpWSGwfxoGPMjY8OT5o3rkeP0XaTAoGBALLR
GQmr4eZtqZDMK+XNpjYgsDvVE7HGRCW7cY17vNFiQruglloiX778BJ7n+7uxye3D
EwuuSj15ncLHwKMsaW2w1GqEEi1azzjfSWxWSnPLPR6aifdtUfueMtsMHXio5dL6
vaV0SXG5UI5b7eDy/bhrW0wOYRQtreIKGZz49jZpAoGBAIvxYngkLwmq6g6MmnAc
YK4oT6YAm2wfSy2mzpEQP5r1igp1rN7T46o7FMUPDLS9wK3ESAaIYe01qT6Yftcc
5qF+yiOGDTr9XQiHwe4BcyrNEMfUjDhDU5ao2gH8+t1VGr1KspLsUNbedrJwZsY4
UCZVKEEDHzKfLO/iBgKjJQF7
-----END PRIVATE KEY-----`)
rsaSigner = mustMakeSigner(jose.RS256, testPrivRSAKey1)
hmacSigner = mustMakeSigner(jose.HS256, sharedKey)
)

View File

@@ -1,115 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 Square, 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 jwt
import (
"encoding/json"
"strconv"
"time"
)
// Claims represents public claim values (as specified in RFC 7519).
type Claims struct {
Issuer string `json:"iss,omitempty"`
Subject string `json:"sub,omitempty"`
Audience Audience `json:"aud,omitempty"`
Expiry NumericDate `json:"exp,omitempty"`
NotBefore NumericDate `json:"nbf,omitempty"`
IssuedAt NumericDate `json:"iat,omitempty"`
ID string `json:"jti,omitempty"`
}
// NumericDate represents date and time as the number of seconds since the
// epoch, including leap seconds. Non-integer values can be represented
// in the serialized format, but we round to the nearest second.
type NumericDate int64
// NewNumericDate constructs NumericDate from time.Time value.
func NewNumericDate(t time.Time) NumericDate {
if t.IsZero() {
return NumericDate(0)
}
// While RFC 7519 technically states that NumericDate values may be
// non-integer values, we don't bother serializing timestamps in
// claims with sub-second accurancy and just round to the nearest
// second instead. Not convined sub-second accuracy is useful here.
return NumericDate(t.Unix())
}
// MarshalJSON serializes the given NumericDate into its JSON representation.
func (n NumericDate) MarshalJSON() ([]byte, error) {
return []byte(strconv.FormatInt(int64(n), 10)), nil
}
// UnmarshalJSON reads a date from its JSON representation.
func (n *NumericDate) UnmarshalJSON(b []byte) error {
s := string(b)
f, err := strconv.ParseFloat(s, 64)
if err != nil {
return ErrUnmarshalNumericDate
}
*n = NumericDate(f)
return nil
}
// Time returns time.Time representation of NumericDate.
func (n NumericDate) Time() time.Time {
return time.Unix(int64(n), 0)
}
// Audience represents the recipents that the token is intended for.
type Audience []string
// UnmarshalJSON reads an audience from its JSON representation.
func (s *Audience) UnmarshalJSON(b []byte) error {
var v interface{}
if err := json.Unmarshal(b, &v); err != nil {
return err
}
switch v := v.(type) {
case string:
*s = []string{v}
case []interface{}:
a := make([]string, len(v))
for i, e := range v {
s, ok := e.(string)
if !ok {
return ErrUnmarshalAudience
}
a[i] = s
}
*s = a
default:
return ErrUnmarshalAudience
}
return nil
}
func (s Audience) Contains(v string) bool {
for _, a := range s {
if a == v {
return true
}
}
return false
}

View File

@@ -1,80 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 Square, 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 jwt
import (
"testing"
"time"
"gopkg.in/square/go-jose.v2/json"
"github.com/stretchr/testify/assert"
)
func TestEncodeClaims(t *testing.T) {
now := time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)
c := Claims{
Issuer: "issuer",
Subject: "subject",
Audience: Audience{"a1", "a2"},
NotBefore: NewNumericDate(time.Time{}),
IssuedAt: NewNumericDate(now),
Expiry: NewNumericDate(now.Add(1 * time.Hour)),
}
b, err := json.Marshal(c)
assert.NoError(t, err)
expected := `{"iss":"issuer","sub":"subject","aud":["a1","a2"],"exp":1451610000,"iat":1451606400}`
assert.Equal(t, expected, string(b))
}
func TestDecodeClaims(t *testing.T) {
s := []byte(`{"iss":"issuer","sub":"subject","aud":["a1","a2"],"exp":1451610000,"iat":1451606400}`)
now := time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)
c := Claims{}
if err := json.Unmarshal(s, &c); assert.NoError(t, err) {
assert.Equal(t, "issuer", c.Issuer)
assert.Equal(t, "subject", c.Subject)
assert.Equal(t, Audience{"a1", "a2"}, c.Audience)
assert.True(t, now.Equal(c.IssuedAt.Time()))
assert.True(t, now.Add(1*time.Hour).Equal(c.Expiry.Time()))
}
s2 := []byte(`{"aud": "a1"}`)
c2 := Claims{}
if err := json.Unmarshal(s2, &c2); assert.NoError(t, err) {
assert.Equal(t, Audience{"a1"}, c2.Audience)
}
invalid := []struct {
Raw string
Err error
}{
{`{"aud": 5}`, ErrUnmarshalAudience},
{`{"aud": ["foo", 5, "bar"]}`, ErrUnmarshalAudience},
{`{"exp": "invalid"}`, ErrUnmarshalNumericDate},
}
for _, v := range invalid {
c := Claims{}
assert.Equal(t, v.Err, json.Unmarshal([]byte(v.Raw), &c))
}
}

View File

@@ -1,47 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 Square, 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 jwt
import "errors"
// ErrUnmarshalAudience indicates that aud claim could not be unmarshalled.
var ErrUnmarshalAudience = errors.New("square/go-jose/jwt: expected string or array value to unmarshal to Audience")
// ErrUnmarshalNumericDate indicates that JWT NumericDate could not be unmarshalled.
var ErrUnmarshalNumericDate = errors.New("square/go-jose/jwt: expected number value to unmarshal NumericDate")
// ErrInvalidClaims indicates that given claims have invalid type.
var ErrInvalidClaims = errors.New("square/go-jose/jwt: expected claims to be value convertible into JSON object")
// ErrInvalidIssuer indicates invalid iss claim.
var ErrInvalidIssuer = errors.New("square/go-jose/jwt: validation failed, invalid issuer claim (iss)")
// ErrInvalidSubject indicates invalid sub claim.
var ErrInvalidSubject = errors.New("square/go-jose/jwt: validation failed, invalid subject claim (sub)")
// ErrInvalidAudience indicated invalid aud claim.
var ErrInvalidAudience = errors.New("square/go-jose/jwt: validation failed, invalid audience claim (aud)")
// ErrInvalidID indicates invalid jti claim.
var ErrInvalidID = errors.New("square/go-jose/jwt: validation failed, invalid ID claim (jti)")
// ErrNotValidYet indicates that token is used before time indicated in nbf claim.
var ErrNotValidYet = errors.New("square/go-jose/jwt: validation failed, token not valid yet (nbf)")
// ErrExpired indicates that token is used after expiry time indicated in exp claim.
var ErrExpired = errors.New("square/go-jose/jwt: validation failed, token is expired (exp)")

View File

@@ -1,200 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 Square, 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 jwt_test
import (
"fmt"
"strings"
"time"
"gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
)
var sharedKey = []byte("secret")
var sharedEncryptionKey = []byte("itsa16bytesecret")
var signer, _ = jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: sharedKey}, &jose.SignerOptions{})
func ExampleParseSigned() {
raw := `eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzdWIiOiJzdWJqZWN0In0.gpHyA1B1H6X4a4Edm9wo7D3X2v3aLSDBDG2_5BzXYe0`
tok, err := jwt.ParseSigned(raw)
if err != nil {
panic(err)
}
out := jwt.Claims{}
if err := tok.Claims(sharedKey, &out); err != nil {
panic(err)
}
fmt.Printf("iss: %s, sub: %s\n", out.Issuer, out.Subject)
// Output: iss: issuer, sub: subject
}
func ExampleParseEncrypted() {
key := []byte("itsa16bytesecret")
raw := `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..jg45D9nmr6-8awml.z-zglLlEw9MVkYHi-Znd9bSwc-oRGbqKzf9WjXqZxno.kqji2DiZHZmh-1bLF6ARPw`
tok, err := jwt.ParseEncrypted(raw)
if err != nil {
panic(err)
}
out := jwt.Claims{}
if err := tok.Claims(key, &out); err != nil {
panic(err)
}
fmt.Printf("iss: %s, sub: %s\n", out.Issuer, out.Subject)
//Output: iss: issuer, sub: subject
}
func ExampleClaims_Validate() {
cl := jwt.Claims{
Subject: "subject",
Issuer: "issuer",
NotBefore: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
Expiry: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 15, 0, 0, time.UTC)),
Audience: jwt.Audience{"leela", "fry"},
}
err := cl.Validate(jwt.Expected{
Issuer: "issuer",
Time: time.Date(2016, 1, 1, 0, 10, 0, 0, time.UTC),
})
if err != nil {
panic(err)
}
fmt.Printf("valid!")
// Output: valid!
}
func ExampleClaims_Validate_withParse() {
raw := `eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzdWIiOiJzdWJqZWN0In0.gpHyA1B1H6X4a4Edm9wo7D3X2v3aLSDBDG2_5BzXYe0`
tok, err := jwt.ParseSigned(raw)
if err != nil {
panic(err)
}
cl := jwt.Claims{}
if err := tok.Claims(sharedKey, &cl); err != nil {
panic(err)
}
err = cl.Validate(jwt.Expected{
Issuer: "issuer",
Subject: "subject",
})
if err != nil {
panic(err)
}
fmt.Printf("valid!")
// Output: valid!
}
func ExampleSigned() {
key := []byte("secret")
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: key}, &jose.SignerOptions{})
if err != nil {
panic(err)
}
cl := jwt.Claims{
Subject: "subject",
Issuer: "issuer",
NotBefore: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
Audience: jwt.Audience{"leela", "fry"},
}
raw, err := jwt.Signed(sig).Claims(cl).CompactSerialize()
if err != nil {
panic(err)
}
fmt.Println(raw)
// Output: eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsibGVlbGEiLCJmcnkiXSwiaXNzIjoiaXNzdWVyIiwibmJmIjoxLjQ1MTYwNjRlKzA5LCJzdWIiOiJzdWJqZWN0In0.uazfxZNgnlLdNDK7JkuYj3LlT4jSyEDG8EWISBPUuME
}
func ExampleEncrypted() {
enc, err := jose.NewEncrypter(jose.A128GCM, jose.Recipient{Algorithm: jose.DIRECT, Key: sharedEncryptionKey}, nil)
if err != nil {
panic(err)
}
cl := jwt.Claims{
Subject: "subject",
Issuer: "issuer",
}
raw, err := jwt.Encrypted(enc).Claims(cl).CompactSerialize()
if err != nil {
panic(err)
}
fmt.Println(raw)
}
func ExampleSigned_multipleClaims() {
c := &jwt.Claims{
Subject: "subject",
Issuer: "issuer",
}
c2 := struct {
Scopes []string
}{
[]string{"foo", "bar"},
}
raw, err := jwt.Signed(signer).Claims(c).Claims(c2).CompactSerialize()
if err != nil {
panic(err)
}
fmt.Println(raw)
// Output: eyJhbGciOiJIUzI1NiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sImlzcyI6Imlzc3VlciIsInN1YiI6InN1YmplY3QifQ.esKOIsmwkudr_gnfnB4SngxIr-7pspd5XzG3PImfQ6Y
}
func ExampleJSONWebToken_Claims_map() {
raw := `eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzdWIiOiJzdWJqZWN0In0.gpHyA1B1H6X4a4Edm9wo7D3X2v3aLSDBDG2_5BzXYe0`
tok, err := jwt.ParseSigned(raw)
if err != nil {
panic(err)
}
out := make(map[string]interface{})
if err := tok.Claims(sharedKey, &out); err != nil {
panic(err)
}
fmt.Printf("iss: %s, sub: %s\n", out["iss"], out["sub"])
// Output: iss: issuer, sub: subject
}
func ExampleJSONWebToken_Claims_multiple() {
raw := `eyJhbGciOiJIUzI1NiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sImlzcyI6Imlzc3VlciIsInN1YiI6InN1YmplY3QifQ.esKOIsmwkudr_gnfnB4SngxIr-7pspd5XzG3PImfQ6Y`
tok, err := jwt.ParseSigned(raw)
if err != nil {
panic(err)
}
out := jwt.Claims{}
out2 := struct {
Scopes []string
}{}
if err := tok.Claims(sharedKey, &out, &out2); err != nil {
panic(err)
}
fmt.Printf("iss: %s, sub: %s, scopes: %s\n", out.Issuer, out.Subject, strings.Join(out2.Scopes, ","))
// Output: iss: issuer, sub: subject, scopes: foo,bar
}

View File

@@ -1,69 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 Square, 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 jwt
import (
"gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/json"
)
// JSONWebToken represents a JSON Web Token (as specified in RFC7519).
type JSONWebToken struct {
payload func(k interface{}) ([]byte, error)
Headers []jose.Header
}
// Claims deserializes a JSONWebToken into dest using the provided key.
func (t *JSONWebToken) Claims(key interface{}, dest ...interface{}) error {
b, err := t.payload(key)
if err != nil {
return err
}
for _, d := range dest {
if err := json.Unmarshal(b, d); err != nil {
return err
}
}
return nil
}
// ParseSigned parses token from JWS form.
func ParseSigned(s string) (*JSONWebToken, error) {
sig, err := jose.ParseSigned(s)
if err != nil {
return nil, err
}
headers := make([]jose.Header, len(sig.Signatures))
for i, signature := range sig.Signatures {
headers[i] = signature.Header
}
return &JSONWebToken{sig.Verify, headers}, nil
}
// ParseEncrypted parses token from JWE form.
func ParseEncrypted(s string) (*JSONWebToken, error) {
enc, err := jose.ParseEncrypted(s)
if err != nil {
return nil, err
}
return &JSONWebToken{enc.Decrypt, []jose.Header{enc.Header}}, nil
}

View File

@@ -1,116 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 Square, 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 jwt
import (
"testing"
"github.com/stretchr/testify/assert"
)
var (
hmacSignedToken = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiaXNzIjoiaXNzdWVyIiwic2NvcGVzIjpbInMxIiwiczIiXX0.Y6_PfQHrzRJ_Vlxij5VI07-pgDIuJNN3Z_g5sSaGQ0c`
rsaSignedToken = `eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzY29wZXMiOlsiczEiLCJzMiJdLCJzdWIiOiJzdWJqZWN0In0.UDDtyK9gC9kyHltcP7E_XODsnqcJWZIiXeGmSAH7SE9YKy3N0KSfFIN85dCNjTfs6zvy4rkrCHzLB7uKAtzMearh3q7jL4nxbhUMhlUcs_9QDVoN4q_j58XmRqBqRnBk-RmDu9TgcV8RbErP4awpIhwWb5UU-hR__4_iNbHdKqwSUPDKYGlf5eicuiYrPxH8mxivk4LRD-vyRdBZZKBt0XIDnEU4TdcNCzAXojkftqcFWYsczwS8R4JHd1qYsMyiaWl4trdHZkO4QkeLe34z4ZAaPMt3wE-gcU-VoqYTGxz-K3Le2VaZ0r3j_z6bOInsv0yngC_cD1dCXMyQJWnWjQ`
invalidPayloadSignedToken = `eyJhbGciOiJIUzI1NiJ9.aW52YWxpZC1wYXlsb2Fk.ScBKKm18jcaMLGYDNRUqB5gVMRZl4DM6dh3ShcxeNgY`
invalidPartsSignedToken = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiaXNzIjoiaXNzdWVyIiwic2NvcGVzIjpbInMxIiwiczIiXX0`
hmacEncryptedToken = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..NZrU98U4QNO0y-u6.HSq5CvlmkUT1BPqLGZ4.1-zuiZ4RbHrTTUoA8Dvfhg`
rsaEncryptedToken = `eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.IvkVHHiI8JwwavvTR80xGjYvkzubMrZ-TDDx8k8SNJMEylfFfNUc7F2rC3WAABF_xmJ3SW2A6on-S6EAG97k0RsjqHHNqZuaFpDvjeuLqZFfYKzI45aCtkGG4C2ij2GbeySqJ784CcvFJPUWJ-6VPN2Ho2nhefUSqig0jE2IvOKy1ywTj_VBVBxF_dyXFnXwxPKGUQr3apxrWeRJfDh2Cf8YPBlLiRznjfBfwgePB1jP7WCZNwItj10L7hsT_YWEx01XJcbxHaXFLwKyVzwWaDhreFyaWMRbGqEfqVuOT34zfmhLDhQlgLLwkXrvYqX90NsQ9Ftg0LLIfRMbsfdgug.BFy2Tj1RZN8yq2Lk-kMiZQ.9Z0eOyPiv5cEzmXh64RlAQ36Uvz0WpZgqRcc2_69zHTmUOv0Vnl1I6ks8sTraUEvukAilolNBjBj47s0b4b-Og.VM8-eJg5ZsqnTqs0LtGX_Q`
invalidPayloadEncryptedToken = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..T4jCS4Yyw1GCH0aW.y4gFaMITdBs_QZM8RKrL.6MPyk1cMVaOJFoNGlEuaRQ`
invalidPartsEncryptedToken = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..NZrU98U4QNO0y-u6.HSq5CvlmkUT1BPqLGZ4`
)
type customClaims struct {
Scopes []string `json:"scopes,omitempty"`
}
func TestDecodeToken(t *testing.T) {
tok, err := ParseSigned(hmacSignedToken)
if assert.NoError(t, err, "Error parsing signed token.") {
c := &Claims{}
c2 := &customClaims{}
if assert.NoError(t, tok.Claims(sharedKey, c, c2)) {
assert.Equal(t, "subject", c.Subject)
assert.Equal(t, "issuer", c.Issuer)
assert.Equal(t, []string{"s1", "s2"}, c2.Scopes)
}
}
assert.EqualError(t, tok.Claims([]byte("invalid-secret")), "square/go-jose: error in cryptographic primitive")
tok2, err := ParseSigned(rsaSignedToken)
if assert.NoError(t, err, "Error parsing encrypted token.") {
c := make(map[string]interface{})
if assert.NoError(t, tok2.Claims(&testPrivRSAKey1.PublicKey, &c)) {
assert.Equal(t, map[string]interface{}{
"sub": "subject",
"iss": "issuer",
"scopes": []interface{}{"s1", "s2"},
}, c)
}
}
assert.EqualError(t, tok.Claims(&testPrivRSAKey2.PublicKey), "square/go-jose: error in cryptographic primitive")
tok3, err := ParseSigned(invalidPayloadSignedToken)
if assert.NoError(t, err, "Error parsing signed token.") {
assert.Error(t, tok3.Claims(sharedKey, &Claims{}), "Expected unmarshaling claims to fail.")
}
_, err = ParseSigned(invalidPartsSignedToken)
assert.EqualError(t, err, "square/go-jose: compact JWS format must have three parts")
tok4, err := ParseEncrypted(hmacEncryptedToken)
if assert.NoError(t, err, "Error parsing encrypted token.") {
c := Claims{}
if assert.NoError(t, tok4.Claims(sharedEncryptionKey, &c)) {
assert.Equal(t, "foo", c.Subject)
}
}
assert.EqualError(t, tok4.Claims([]byte("invalid-secret-key")), "square/go-jose: error in cryptographic primitive")
tok5, err := ParseEncrypted(rsaEncryptedToken)
if assert.NoError(t, err, "Error parsing encrypted token.") {
c := make(map[string]interface{})
if assert.NoError(t, tok5.Claims(testPrivRSAKey1, &c)) {
assert.Equal(t, map[string]interface{}{
"sub": "subject",
"iss": "issuer",
"scopes": []interface{}{"s1", "s2"},
}, c)
}
}
assert.EqualError(t, tok5.Claims(testPrivRSAKey2), "square/go-jose: error in cryptographic primitive")
tok6, err := ParseEncrypted(invalidPayloadEncryptedToken)
if assert.NoError(t, err, "Error parsing encrypted token.") {
assert.Error(t, tok6.Claims(sharedEncryptionKey, &Claims{}))
}
_, err = ParseEncrypted(invalidPartsEncryptedToken)
assert.EqualError(t, err, "square/go-jose: compact JWE format must have five parts")
}
func BenchmarkDecodeSignedToken(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseSigned(hmacSignedToken)
}
}
func BenchmarkDecodeEncryptedHMACToken(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseEncrypted(hmacEncryptedToken)
}
}

View File

@@ -1,93 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 Square, 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 jwt
import "time"
const (
// DefaultLeeway defines the default leeway for matching NotBefore/Expiry claims.
DefaultLeeway = 1.0 * time.Minute
)
// Expected defines values used for protected claims validation.
// If field has zero value then validation is skipped.
type Expected struct {
// Issuer matches the "iss" claim exactly.
Issuer string
// Subject matches the "sub" claim exactly.
Subject string
// Audience matches the values in "aud" claim, regardless of their order.
Audience Audience
// ID matches the "jti" claim exactly.
ID string
// Time matches the "exp" and "ebf" claims with leeway.
Time time.Time
}
// WithTime copies expectations with new time.
func (e Expected) WithTime(t time.Time) Expected {
e.Time = t
return e
}
// Validate checks claims in a token against expected values.
// A default leeway value of one minute is used to compare time values.
func (c Claims) Validate(e Expected) error {
return c.ValidateWithLeeway(e, DefaultLeeway)
}
// ValidateWithLeeway checks claims in a token against expected values. A
// custom leeway may be specified for comparing time values. You may pass a
// zero value to check time values with no leeway, but you should not that
// numeric date values are rounded to the nearest second and sub-second
// precision is not supported.
func (c Claims) ValidateWithLeeway(e Expected, leeway time.Duration) error {
if e.Issuer != "" && e.Issuer != c.Issuer {
return ErrInvalidIssuer
}
if e.Subject != "" && e.Subject != c.Subject {
return ErrInvalidSubject
}
if e.ID != "" && e.ID != c.ID {
return ErrInvalidID
}
if len(e.Audience) != 0 {
if len(e.Audience) != len(c.Audience) {
return ErrInvalidAudience
}
for _, v := range e.Audience {
if !c.Audience.Contains(v) {
return ErrInvalidAudience
}
}
}
if !e.Time.IsZero() && e.Time.Add(leeway).Before(c.NotBefore.Time()) {
return ErrNotValidYet
}
if !e.Time.IsZero() && e.Time.Add(-leeway).After(c.Expiry.Time()) {
return ErrExpired
}
return nil
}

View File

@@ -1,94 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 Square, 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 jwt
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestFieldsMatch(t *testing.T) {
c := Claims{
Issuer: "issuer",
Subject: "subject",
Audience: []string{"a1", "a2"},
ID: "42",
}
valid := []Expected{
{Issuer: "issuer"},
{Subject: "subject"},
{Audience: Audience{"a1", "a2"}},
{Audience: Audience{"a2", "a1"}},
{ID: "42"},
}
for _, v := range valid {
assert.NoError(t, c.Validate(v))
}
invalid := []struct {
Expected Expected
Error error
}{
{Expected{Issuer: "invalid-issuer"}, ErrInvalidIssuer},
{Expected{Subject: "invalid-subject"}, ErrInvalidSubject},
{Expected{Audience: Audience{"a1"}}, ErrInvalidAudience},
{Expected{Audience: Audience{"a1", "invalid-audience"}}, ErrInvalidAudience},
{Expected{Audience: Audience{"invalid-audience"}}, ErrInvalidAudience},
{Expected{ID: "invalid-id"}, ErrInvalidID},
}
for _, v := range invalid {
assert.Equal(t, v.Error, c.Validate(v.Expected))
}
}
func TestExpiryAndNotBefore(t *testing.T) {
now := time.Date(2016, 1, 1, 12, 0, 0, 0, time.UTC)
twelveHoursAgo := now.Add(-12 * time.Hour)
c := Claims{
IssuedAt: NewNumericDate(twelveHoursAgo),
NotBefore: NewNumericDate(twelveHoursAgo),
Expiry: NewNumericDate(now),
}
// expired - default leeway (1 minute)
assert.NoError(t, c.Validate(Expected{Time: now}))
err := c.Validate(Expected{Time: now.Add(2 * DefaultLeeway)})
if assert.Error(t, err) {
assert.Equal(t, err, ErrExpired)
}
// expired - no leeway
assert.NoError(t, c.ValidateWithLeeway(Expected{Time: now}, 0))
err = c.ValidateWithLeeway(Expected{Time: now.Add(1 * time.Second)}, 0)
if assert.Error(t, err) {
assert.Equal(t, err, ErrExpired)
}
// not before - default leeway (1 minute)
assert.NoError(t, c.Validate(Expected{Time: twelveHoursAgo}))
err = c.Validate(Expected{Time: twelveHoursAgo.Add(-2 * DefaultLeeway)})
if assert.Error(t, err) {
assert.Equal(t, err, ErrNotValidYet)
}
}