github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/pkg/usertokens/pkitokens/jwt_test.go (about)

     1  // +build !windows
     2  
     3  package pkitokens
     4  
     5  import (
     6  	"context"
     7  	"crypto"
     8  	"testing"
     9  
    10  	. "github.com/smartystreets/goconvey/convey"
    11  )
    12  
    13  func TestPKIVerifierValidate(t *testing.T) {
    14  
    15  	ctx := context.TODO()
    16  	pemBytes := []byte(`
    17  -----BEGIN PUBLIC KEY-----
    18  MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyjDEPJD1Fv1IJIq4mnec
    19  oMlSve0vZOTuzDmKuMB4vfBXalKZgbp4ONL+BvWV9OPs22Smv9SAfnoQ25q8Q9so
    20  ihzUKhaIAY2CI70ll4exbLK9FD4uTi1bqn0FdIh04UIyW6s2EqTGMkSKx9THNvAM
    21  Kx++pPt3US2sQVEC24bWPxRN7RsBBpRjoiEamkA04ioGFhMBbas5MdCLt/fd92aR
    22  QCBISOb6PU08fQiARK8g/wdpBUTxy9/Ud1vUnNaZtWm+eLrwdTXgHM3/LG1M4lc0
    23  ZqHIL3rMxhae5W+j3SL3ApreiUYugv/0bCSypvJZjEXKS7SBR/+rtw0/mQpS8DpI
    24  kwIDAQAB
    25  -----END PUBLIC KEY-----
    26  -----BEGIN PUBLIC KEY-----
    27  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnlK01BDTYbvRBxGM0o3vXNqqvI25
    28  eZ/s3Cq9OXnNpoCI3/DH/tuD3n7cnWcNSfl1qJIH2LVZ0cWUW/L/9i/jPA==
    29  -----END PUBLIC KEY-----
    30  	`)
    31  
    32  	// Here are the private keys in case you want to regenerate a new token:
    33  	//
    34  	// -----BEGIN RSA PRIVATE KEY-----
    35  	// MIIEpAIBAAKCAQEAyjDEPJD1Fv1IJIq4mnecoMlSve0vZOTuzDmKuMB4vfBXalKZ
    36  	// gbp4ONL+BvWV9OPs22Smv9SAfnoQ25q8Q9soihzUKhaIAY2CI70ll4exbLK9FD4u
    37  	// Ti1bqn0FdIh04UIyW6s2EqTGMkSKx9THNvAMKx++pPt3US2sQVEC24bWPxRN7RsB
    38  	// BpRjoiEamkA04ioGFhMBbas5MdCLt/fd92aRQCBISOb6PU08fQiARK8g/wdpBUTx
    39  	// y9/Ud1vUnNaZtWm+eLrwdTXgHM3/LG1M4lc0ZqHIL3rMxhae5W+j3SL3ApreiUYu
    40  	// gv/0bCSypvJZjEXKS7SBR/+rtw0/mQpS8DpIkwIDAQABAoIBAQCWkraxfCpp0nn1
    41  	// bLGJp2Ynf4Z1Frvi4XLM+FVMvVmt6dzPu2/CYsHBX6/6Ms5YL51mzZA47+I5TmJb
    42  	// iOKHjiCkqk9+gIUM0vuF7giezljdYEbbWmtVoQXQ84YqgKy6THgAOILuY3OOX+kS
    43  	// ZG1vhlkpjFyHtRXoiKDti40bO1E2a2+O/vpD417hZrezzb97JQ4Cw417jRs3+dpc
    44  	// BaVutFUiIm5HFeVdD0/hqwnYMPeoxxxdj4kiuzI2FZOexPufq9MSrSI0RMnegRGL
    45  	// 8fgg4ZhVuEONtA8eXFI8EpIEhaKOq9CPZuImyKh+Vx4pwcT7NVld70ohqhQaEVqs
    46  	// 6QblHf6hAoGBAOqimWdjGY6PKT6ipF9/6CsNnAAyyG1IRWSLweVDK36DkIxzTKGU
    47  	// fk2uXFw6GlAKu1J0lTfQjxtKoYVljUHjUvfvW9KE/GyuW6eWTxUIrvmpvpcyAV6H
    48  	// gHkt8/A+l8sQS3oMiLJ14c8/W5d4YdB/VBLQHsOi8I5EOGsO7a52fETLAoGBANyZ
    49  	// 3+nq/tyk6hGk+lNJSXnkURydbkONCFhU92iwPC+f/4ILcHdBVjwLOAYa/qUzHvEE
    50  	// H+MtMiuGbDrnjjCytvjmIKmMnJ30BHbXwn0dV+hes1O0EwHoIGtvQyWVH/6zB4ar
    51  	// YkhK9IBtOxfs3ORVeVBoHx/Mq40BAGzGxQQopVpZAoGAScFtCWPMb9SuuWK02tRB
    52  	// Le9sP1+3Qyr5rT6FZ8TykiVXNd80koI0JcUOgWs+RDTrZ2MAWPg1U/XkyiL/AVwt
    53  	// A4T5TzbAhoVUiFymZU1Ce3aRU8PDTGy5xN3eFYIHgyyPHUF9YuPNZLFc4ENWNA0i
    54  	// Z3uGgCbjCUWGmpipvDLAo3sCgYApQEDlvgLAgbofaIlCz76Eo5QjVLEMwq+fzOui
    55  	// 0OnAQhwGVltGgZo9ih+EzMF3ZNLRYOMRmR77kpxke25UXubmLipHajrTMpEvI/OD
    56  	// b9xDYIoKCe9P+Pcu/9Q/j942w4WRwjSTriiAZ2yYcbtwmycfSQkg6iXeLSTGMnke
    57  	// 6PbaqQKBgQDGNwOgdHtMdHyy2kDMLdGKCysEo2eBNAxdRqjGxmsjm6bsd4xyLxS2
    58  	// lkf7v3e9vE24HfBbwMoW4sx1eEDbFc4pai4l4vG3dpbrd3CJa5mpvL3mxGnTlPUy
    59  	// 1PopL5pyjSZ6bcRETolZNM4L8X4jgfwHl3Lvc5jBgQW0PCAVtBVp8g==
    60  	// -----END RSA PRIVATE KEY-----
    61  	//
    62  	// -----BEGIN EC PRIVATE KEY-----
    63  	// MHcCAQEEIBP/5KHpYJ1GwqdOUOCu4+264KP4loONT+9QIzNJwVGjoAoGCCqGSM49
    64  	// AwEHoUQDQgAEnlK01BDTYbvRBxGM0o3vXNqqvI25eZ/s3Cq9OXnNpoCI3/DH/tuD
    65  	// 3n7cnWcNSfl1qJIH2LVZ0cWUW/L/9i/jPA==
    66  	// -----END EC PRIVATE KEY-----
    67  	//
    68  	// And here is the payload data:
    69  	//
    70  	// {
    71  	// 	"sub": "Adam",
    72  	// 	"name": "Eve",
    73  	// 	"admin": true,
    74  	// 	"iat": 1516239022
    75  	// }
    76  	//
    77  	// Go to https://jwt.io/ and
    78  	// - select the right algorithm (RS256 / ES256)
    79  	// - fill in the public key
    80  	// - fill in the private key
    81  	// - ensure the token is still valid (shows Signature Verified)
    82  	// - copy the new token from the encoded section
    83  	//
    84  	validTokenRS256 := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJBZGFtIiwibmFtZSI6IkV2ZSIsImFkbWluIjp0cnVlLCJpYXQiOjE1MTYyMzkwMjJ9.WHDAmZzmX50GRSXTvB0MqQl2gFHFrQav-v6V2MdbqGXvmBZXus9Bl965Uuqs8uxdJzDad8Is05kC77iHElTasgQZqLwSTN5-WXpZFsW_EOGVcy0puDgREm2QcD8pQeagy6KxwDs0BAQIWwPSfjTCn05w-CRKveo1t0TsKUSMiZltebaZOtAr9etOAwBHIy7QzexrhIzlG6-7fqMbpsNZ8DbanUBc2fiL6Ogs461TQixBDHoRw2HjykGoPRvH3sy8bSRX5l1olBkRb4kic7xSKhiU_YlvmBo9ybC81TRGUtQZl87aLcnv4foDLtFvNAwTyTxfikt2Ka1peKJNgk82Dw"
    85  	validTokenES256 := "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJBZGFtIiwibmFtZSI6IkV2ZSIsImFkbWluIjp0cnVlLCJpYXQiOjE1MTYyMzkwMjJ9.V9HGK6yEZBbjgEsyhQeU6i0Io1KZaCMVgSC0u6fQTRd2TX4Ac-FSDnf44s89PPm8RCHqBATJdJMspIQM66y9Hw"
    86  
    87  	// currently unsupported algorithm PS256
    88  	unsupportedTokenPS256 := "eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.P9_X1ctIxnnoUpKSWpYw3rF62e-d8LXe3sETuLn4Lhigw5OQhi-mBBKoBMneHy4kimS84zxnMby0FYo9wKM3I3pEg8Qrz0Q00tNhKCwOnZ7Q-e86sW1luK1z82tufF-sZ9_BY_LGQsym0lQmQaHFzLmEDXnOzWsjUThHGVJTI64"
    89  
    90  	// supported algorithm but signed with a different key
    91  	invalidTokenRS256 := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.TCYt5XsITJX1CxPCT8yAV-TVkIEq_PbChOMqsLfRoPsnsgw5WEuts01mq-pQy7UJiN5mgRxD-WUcX16dUEMGlv50aqzpqh4Qktb3rk-BuQy72IFLOqV0G_zS245-kronKb78cPN25DGlcTwLtjPAYuNzVBAh4vGHSrQyHUdBBPM"
    92  
    93  	Convey("Given a valid PEM", t, func() {
    94  
    95  		Convey("it should create a new verifier successfully using NewVerifier()", func() {
    96  			verifier, err := NewVerifier(&PKIJWTVerifier{
    97  				JWTCertPEM: pemBytes,
    98  			})
    99  			So(err, ShouldBeNil)
   100  			So(verifier, ShouldNotBeNil)
   101  			So(len(verifier.keys), ShouldEqual, 2)
   102  		})
   103  
   104  		Convey("it should create a new verifier successfully using NewVerifierFromPEM()", func() {
   105  			verifier, err := NewVerifierFromPEM(pemBytes, "", false, false)
   106  			So(err, ShouldBeNil)
   107  			So(verifier, ShouldNotBeNil)
   108  			So(len(verifier.keys), ShouldEqual, 2)
   109  		})
   110  	})
   111  
   112  	Convey("Given a verifier with no loaded public keys", t, func() {
   113  		verifier := &PKIJWTVerifier{
   114  			JWTCertPEM: pemBytes,
   115  			keys:       []crypto.PublicKey{},
   116  		}
   117  
   118  		Convey("it should fail to validate", func() {
   119  			token := "not empty token"
   120  			_, _, _, err := verifier.Validate(ctx, token)
   121  			So(err, ShouldNotBeNil)
   122  			So(err.Error(), ShouldEqual, "No public keys loaded into verifier")
   123  		})
   124  	})
   125  
   126  	Convey("Given a valid verifier", t, func() {
   127  		verifier, err := NewVerifierFromPEM(pemBytes, "", false, false)
   128  		So(verifier, ShouldNotBeNil)
   129  		So(err, ShouldBeNil)
   130  		So(len(verifier.keys), ShouldEqual, 2)
   131  
   132  		Convey("it should fail to validate an empty token", func() {
   133  			token := ""
   134  			_, _, _, err := verifier.Validate(ctx, token)
   135  			So(err, ShouldNotBeNil)
   136  			So(err.Error(), ShouldEqual, "Empty token")
   137  		})
   138  
   139  		Convey("it should validate a valid RS256 token successfully", func() {
   140  			token := validTokenRS256
   141  			attributes, _, _, err := verifier.Validate(ctx, token)
   142  			So(err, ShouldBeNil)
   143  			So(len(attributes), ShouldBeGreaterThan, 0)
   144  			So(attributes, ShouldContain, "sub=Adam")
   145  			So(attributes, ShouldContain, "name=Eve")
   146  		})
   147  
   148  		Convey("it should validate a valid ES256 token successfully", func() {
   149  			token := validTokenES256
   150  			attributes, _, _, err := verifier.Validate(ctx, token)
   151  			So(err, ShouldBeNil)
   152  			So(len(attributes), ShouldBeGreaterThan, 0)
   153  			So(attributes, ShouldContain, "sub=Adam")
   154  			So(attributes, ShouldContain, "name=Eve")
   155  		})
   156  
   157  		Convey("it should fail to validate a token signed with an unsupported algorithm", func() {
   158  			token := unsupportedTokenPS256
   159  			_, _, _, err := verifier.Validate(ctx, token)
   160  			So(err, ShouldNotBeNil)
   161  			So(err.Error(), ShouldEqual, "Invalid token - errors: [unsupported signing method '*jwt.SigningMethodRSAPSS'; unsupported signing method '*jwt.SigningMethodRSAPSS']")
   162  		})
   163  
   164  		Convey("it should fail to validate a token signed with an unexpected key", func() {
   165  			token := invalidTokenRS256
   166  			_, _, _, err := verifier.Validate(ctx, token)
   167  			So(err, ShouldNotBeNil)
   168  			So(err.Error(), ShouldEqual, "Invalid token - errors: [crypto/rsa: verification error; signing method '*jwt.SigningMethodRSA' and public key type '*ecdsa.PublicKey' mismatch]")
   169  		})
   170  	})
   171  }