verify exp
This commit is contained in:
parent
ca84b8dbca
commit
05db67c8b7
|
@ -7,11 +7,12 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.coolaj86.com/coolaj86/go-mockid/xkeypairs"
|
"git.coolaj86.com/coolaj86/go-mockid/xkeypairs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VerifyJWT will verify both JWT and uncompressed JWS
|
// Verify will verify both JWT and uncompressed JWS
|
||||||
func Verify(w http.ResponseWriter, r *http.Request) {
|
func Verify(w http.ResponseWriter, r *http.Request) {
|
||||||
if "POST" != r.Method {
|
if "POST" != r.Method {
|
||||||
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
||||||
|
@ -55,7 +56,7 @@ func Verify(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal([]byte(protected), &jws.Header); nil != err {
|
if err := json.Unmarshal([]byte(protected), &jws.Header); nil != err {
|
||||||
log.Printf("json decode error: %s", err)
|
log.Printf("json decode header error: %s", err)
|
||||||
http.Error(w, "Bad Request: invalid JWS header", http.StatusBadRequest)
|
http.Error(w, "Bad Request: invalid JWS header", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -66,11 +67,16 @@ func Verify(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal([]byte(payload), &jws.Claims); nil != err {
|
if err := json.Unmarshal([]byte(payload), &jws.Claims); nil != err {
|
||||||
log.Printf("json decode error: %s", err)
|
log.Printf("json decode claims error: %s", err)
|
||||||
http.Error(w, "Bad Request: invalid JWS claims", http.StatusBadRequest)
|
http.Error(w, "Bad Request: invalid JWS claims", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if "false" == r.URL.Query().Get("exp") {
|
||||||
|
//expf64, _ := jws.Claims["exp"].(float64)
|
||||||
|
jws.Claims["exp"] = float64(time.Now().Add(5 * time.Minute).Unix())
|
||||||
|
}
|
||||||
|
|
||||||
ok, err := xkeypairs.VerifyClaims(nil, jws)
|
ok, err := xkeypairs.VerifyClaims(nil, jws)
|
||||||
if nil != err {
|
if nil != err {
|
||||||
log.Printf("jws verify error: %s", err)
|
log.Printf("jws verify error: %s", err)
|
||||||
|
|
|
@ -64,11 +64,39 @@ func TestMain(m *testing.M) {
|
||||||
//func TestSelfSignWithoutExp(t *testing.T)
|
//func TestSelfSignWithoutExp(t *testing.T)
|
||||||
//func TestSelfSignWithJTIWithoutExp(t *testing.T)
|
//func TestSelfSignWithJTIWithoutExp(t *testing.T)
|
||||||
|
|
||||||
func TestVerifySelfSignedJWT(t *testing.T) {
|
func TestVerifyExpired(t *testing.T) {
|
||||||
jwt := "eyJfc2VlZCI6LTEzMDY3NDU1MDQxNDQsImFsZyI6IlJTMjU2IiwiandrIjp7ImUiOiJBUUFCIiwia2lkIjoiSEZ4ZTlGV1dVc2N3bjltaVozSXNJeWMwMjMtbEJ1UmtvOEJpVV9IRG9KOCIsImt0eSI6IlJTQSIsIm4iOiJ2NUZkSTdYaC0wekxWVEVQZl94ekdIUVpDcEZ2MWR2N2h3eHhrVjctYmxpYmt6LXIxUG9lZ3lQYzFXMjZlWFBvd0xQQXQ3a3dHQnVOdjdMVjh5MEtvMkxOZklaXzRILW54SkJPaWIybXlHOVVfQ29WRDBiM3NBWTdmcDd2QlV1bTBXYVM4R3hZOGtYU0ZOS0VTY0NDNVBpSmFyblNISk1PcUdIVm51YmpsSjl5c1NyNmNsaGpxc0R4dU9qOHpxamF2MUFxek1STWVpRl9CREJsOUFoUGNZSHpHN0JtaXB5UEo2XzBwdWNLTi0tUDZDRk92d05SVGx2ek41RmlRM3VHcy1fMHcwQzVMZWJ6N21BNmJNTFdXc0tRRFBvb3cxallCWHJKdVF1WkZoSmxLMmdidm9ZcV85dWhfLUM1Z3pPZnR4UHBCNnhtY3RfelVaeUdwUUxnQlEiLCJ1c2UiOiJzaWcifSwidHlwIjoiSldUIn0.eyJleHAiOjE1OTY2MTQ3NTYsInN1YiI6ImJhbmFuYXMifQ.qHpzlglOfZMzE3CTNAUXld_wC62JTAJuoQfMaNeFa-XPtYB2Maj8_w3YmRZg_q5S6y9ToCmZ8nWd1kuMheA5qBKOUQeQH47Jts5zWLd0UBckIHo5lK4mk0bUWuiNgr7c9DY6k1DIdFaavyWCXbhFwG0X83qlMhQlPh02dDpCuU78Nn2hF3mZETQKpBIVESYtfeU1Xy3OU_am0kwcN2klLcdweOcrLx_ONfcvAGY3KiIdFiz0ViySAsQ39BiSSvoDYqOOOi41Hky67bnyZQOdalQC_95McTeXApzmGXRUE74Gj-S8c9e5it5d4QZLPaQ1JHzUKz1s7TPvThIn58NA-g"
|
jwt := "eyJfc2VlZCI6LTEzMDY3NDU1MDQxNDQsImFsZyI6IlJTMjU2IiwiandrIjp7ImUiOiJBUUFCIiwia2lkIjoiSEZ4ZTlGV1dVc2N3bjltaVozSXNJeWMwMjMtbEJ1UmtvOEJpVV9IRG9KOCIsImt0eSI6IlJTQSIsIm4iOiJ2NUZkSTdYaC0wekxWVEVQZl94ekdIUVpDcEZ2MWR2N2h3eHhrVjctYmxpYmt6LXIxUG9lZ3lQYzFXMjZlWFBvd0xQQXQ3a3dHQnVOdjdMVjh5MEtvMkxOZklaXzRILW54SkJPaWIybXlHOVVfQ29WRDBiM3NBWTdmcDd2QlV1bTBXYVM4R3hZOGtYU0ZOS0VTY0NDNVBpSmFyblNISk1PcUdIVm51YmpsSjl5c1NyNmNsaGpxc0R4dU9qOHpxamF2MUFxek1STWVpRl9CREJsOUFoUGNZSHpHN0JtaXB5UEo2XzBwdWNLTi0tUDZDRk92d05SVGx2ek41RmlRM3VHcy1fMHcwQzVMZWJ6N21BNmJNTFdXc0tRRFBvb3cxallCWHJKdVF1WkZoSmxLMmdidm9ZcV85dWhfLUM1Z3pPZnR4UHBCNnhtY3RfelVaeUdwUUxnQlEiLCJ1c2UiOiJzaWcifSwidHlwIjoiSldUIn0.eyJleHAiOjE1OTY2MTQ3NTYsInN1YiI6ImJhbmFuYXMifQ.qHpzlglOfZMzE3CTNAUXld_wC62JTAJuoQfMaNeFa-XPtYB2Maj8_w3YmRZg_q5S6y9ToCmZ8nWd1kuMheA5qBKOUQeQH47Jts5zWLd0UBckIHo5lK4mk0bUWuiNgr7c9DY6k1DIdFaavyWCXbhFwG0X83qlMhQlPh02dDpCuU78Nn2hF3mZETQKpBIVESYtfeU1Xy3OU_am0kwcN2klLcdweOcrLx_ONfcvAGY3KiIdFiz0ViySAsQ39BiSSvoDYqOOOi41Hky67bnyZQOdalQC_95McTeXApzmGXRUE74Gj-S8c9e5it5d4QZLPaQ1JHzUKz1s7TPvThIn58NA-g"
|
||||||
client := srv.Client()
|
client := srv.Client()
|
||||||
urlstr, _ := url.Parse(srv.URL + "/verify")
|
urlstr, _ := url.Parse(srv.URL + "/verify")
|
||||||
|
|
||||||
|
req := &http.Request{
|
||||||
|
Method: "POST",
|
||||||
|
URL: urlstr,
|
||||||
|
Header: http.Header{},
|
||||||
|
}
|
||||||
|
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", jwt))
|
||||||
|
res, err := client.Do(req)
|
||||||
|
if nil != err {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data, err := ioutil.ReadAll(res.Body)
|
||||||
|
if nil != err {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if 200 == res.StatusCode {
|
||||||
|
log.Printf(string(data))
|
||||||
|
t.Error(fmt.Errorf("did not expect successful status code: %d", res.StatusCode))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerifySelfSignedJWT(t *testing.T) {
|
||||||
|
jwt := "eyJfc2VlZCI6LTEzMDY3NDU1MDQxNDQsImFsZyI6IlJTMjU2IiwiandrIjp7ImUiOiJBUUFCIiwia2lkIjoiSEZ4ZTlGV1dVc2N3bjltaVozSXNJeWMwMjMtbEJ1UmtvOEJpVV9IRG9KOCIsImt0eSI6IlJTQSIsIm4iOiJ2NUZkSTdYaC0wekxWVEVQZl94ekdIUVpDcEZ2MWR2N2h3eHhrVjctYmxpYmt6LXIxUG9lZ3lQYzFXMjZlWFBvd0xQQXQ3a3dHQnVOdjdMVjh5MEtvMkxOZklaXzRILW54SkJPaWIybXlHOVVfQ29WRDBiM3NBWTdmcDd2QlV1bTBXYVM4R3hZOGtYU0ZOS0VTY0NDNVBpSmFyblNISk1PcUdIVm51YmpsSjl5c1NyNmNsaGpxc0R4dU9qOHpxamF2MUFxek1STWVpRl9CREJsOUFoUGNZSHpHN0JtaXB5UEo2XzBwdWNLTi0tUDZDRk92d05SVGx2ek41RmlRM3VHcy1fMHcwQzVMZWJ6N21BNmJNTFdXc0tRRFBvb3cxallCWHJKdVF1WkZoSmxLMmdidm9ZcV85dWhfLUM1Z3pPZnR4UHBCNnhtY3RfelVaeUdwUUxnQlEiLCJ1c2UiOiJzaWcifSwidHlwIjoiSldUIn0.eyJleHAiOjE1OTY2MTQ3NTYsInN1YiI6ImJhbmFuYXMifQ.qHpzlglOfZMzE3CTNAUXld_wC62JTAJuoQfMaNeFa-XPtYB2Maj8_w3YmRZg_q5S6y9ToCmZ8nWd1kuMheA5qBKOUQeQH47Jts5zWLd0UBckIHo5lK4mk0bUWuiNgr7c9DY6k1DIdFaavyWCXbhFwG0X83qlMhQlPh02dDpCuU78Nn2hF3mZETQKpBIVESYtfeU1Xy3OU_am0kwcN2klLcdweOcrLx_ONfcvAGY3KiIdFiz0ViySAsQ39BiSSvoDYqOOOi41Hky67bnyZQOdalQC_95McTeXApzmGXRUE74Gj-S8c9e5it5d4QZLPaQ1JHzUKz1s7TPvThIn58NA-g"
|
||||||
|
client := srv.Client()
|
||||||
|
urlstr, _ := url.Parse(srv.URL + "/verify?exp=false")
|
||||||
|
|
||||||
req := &http.Request{
|
req := &http.Request{
|
||||||
Method: "POST",
|
Method: "POST",
|
||||||
URL: urlstr,
|
URL: urlstr,
|
||||||
|
|
|
@ -13,20 +13,27 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"math/big"
|
"math/big"
|
||||||
mathrand "math/rand"
|
mathrand "math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.rootprojects.org/root/keypairs"
|
"git.rootprojects.org/root/keypairs"
|
||||||
)
|
)
|
||||||
|
|
||||||
func VerifyClaims(pubkey keypairs.PublicKey, jws *JWS) (bool, error) {
|
func VerifyClaims(pubkey keypairs.PublicKey, jws *JWS) (bool, error) {
|
||||||
seed, _ := jws.Header["_seed"].(int64)
|
seed, _ := jws.Header["_seed"].(int64)
|
||||||
|
seedf64, _ := jws.Header["_seed"].(float64)
|
||||||
kty, _ := jws.Header["_kty"].(string)
|
kty, _ := jws.Header["_kty"].(string)
|
||||||
kid, _ := jws.Header["kid"].(string)
|
kid, _ := jws.Header["kid"].(string)
|
||||||
jwkmap, hasJWK := jws.Header["jwk"].(Object)
|
jwkmap, hasJWK := jws.Header["jwk"].(Object)
|
||||||
//var jwk JWK = nil
|
//var jwk JWK = nil
|
||||||
|
|
||||||
|
if 0 == seed {
|
||||||
|
seed = int64(seedf64)
|
||||||
|
}
|
||||||
|
|
||||||
var pub keypairs.PublicKey = nil
|
var pub keypairs.PublicKey = nil
|
||||||
if hasJWK {
|
if hasJWK {
|
||||||
fmt.Println("Security TODO: did not check jws.Claims[\"sub\"] against 'jwk' thumbprint")
|
log.Println("Security TODO: did not check jws.Claims[\"sub\"] against 'jwk' thumbprint")
|
||||||
fmt.Println("Security TODO: did not check jws.Claims[\"iss\"]")
|
log.Println("Security TODO: did not check jws.Claims[\"iss\"]")
|
||||||
kty := jwkmap["kty"]
|
kty := jwkmap["kty"]
|
||||||
var err error
|
var err error
|
||||||
if "RSA" == kty {
|
if "RSA" == kty {
|
||||||
|
@ -70,7 +77,20 @@ func VerifyClaims(pubkey keypairs.PublicKey, jws *JWS) (bool, error) {
|
||||||
} else {
|
} else {
|
||||||
pub = pubkey
|
pub = pubkey
|
||||||
}
|
}
|
||||||
fmt.Println("Security TODO: did not check jws.Claims[\"kid\"] against thumbprint")
|
log.Println("Security TODO: did not check jws.Claims[\"kid\"] against thumbprint")
|
||||||
|
}
|
||||||
|
|
||||||
|
jti, _ := jws.Claims["jti"].(string)
|
||||||
|
expf64, _ := jws.Claims["exp"].(float64)
|
||||||
|
exp := int64(expf64)
|
||||||
|
if 0 == exp {
|
||||||
|
if "" == jti {
|
||||||
|
return false, errors.New("one of 'jti' or 'exp' must exist for token expiry")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if time.Now().Unix() > exp {
|
||||||
|
return false, fmt.Errorf("token expired at %d (%s)", exp, time.Unix(exp, 0))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signable := fmt.Sprintf("%s.%s", jws.Protected, jws.Payload)
|
signable := fmt.Sprintf("%s.%s", jws.Protected, jws.Payload)
|
||||||
|
@ -103,8 +123,6 @@ func Verify(pubkey keypairs.PublicKey, hash []byte, sig []byte) bool {
|
||||||
r.SetBytes(sig[0:32])
|
r.SetBytes(sig[0:32])
|
||||||
s := &big.Int{}
|
s := &big.Int{}
|
||||||
s.SetBytes(sig[32:])
|
s.SetBytes(sig[32:])
|
||||||
fmt.Println("debug: sig len:", len(sig))
|
|
||||||
fmt.Println("debug: r, s:", r, s)
|
|
||||||
return ecdsa.Verify(pub, hash, r, s)
|
return ecdsa.Verify(pub, hash, r, s)
|
||||||
default:
|
default:
|
||||||
panic("impossible condition: non-rsa/non-ecdsa key")
|
panic("impossible condition: non-rsa/non-ecdsa key")
|
||||||
|
@ -134,6 +152,7 @@ func genPrivKey(seed int64, kty string) keypairs.PrivateKey {
|
||||||
}
|
}
|
||||||
if maxRetry == i-1 {
|
if maxRetry == i-1 {
|
||||||
log.Printf("error: coinflip landed on heads %d times", maxRetry)
|
log.Printf("error: coinflip landed on heads %d times", maxRetry)
|
||||||
|
// TODO return random / retry error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue