...

Source file src/gopkg.in/go-jose/go-jose.v2/jwt/jwt_test.go

Documentation: gopkg.in/go-jose/go-jose.v2/jwt

     1  /*-
     2   * Copyright 2016 Zbigniew Mandziejewicz
     3   * Copyright 2016 Square, Inc.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package jwt
    19  
    20  import (
    21  	"strings"
    22  	"testing"
    23  
    24  	"github.com/stretchr/testify/assert"
    25  	jose "gopkg.in/go-jose/go-jose.v2"
    26  )
    27  
    28  var (
    29  	hmacSignedToken                = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiaXNzIjoiaXNzdWVyIiwic2NvcGVzIjpbInMxIiwiczIiXX0.Y6_PfQHrzRJ_Vlxij5VI07-pgDIuJNN3Z_g5sSaGQ0c`
    30  	rsaSignedToken                 = `eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzY29wZXMiOlsiczEiLCJzMiJdLCJzdWIiOiJzdWJqZWN0In0.UDDtyK9gC9kyHltcP7E_XODsnqcJWZIiXeGmSAH7SE9YKy3N0KSfFIN85dCNjTfs6zvy4rkrCHzLB7uKAtzMearh3q7jL4nxbhUMhlUcs_9QDVoN4q_j58XmRqBqRnBk-RmDu9TgcV8RbErP4awpIhwWb5UU-hR__4_iNbHdKqwSUPDKYGlf5eicuiYrPxH8mxivk4LRD-vyRdBZZKBt0XIDnEU4TdcNCzAXojkftqcFWYsczwS8R4JHd1qYsMyiaWl4trdHZkO4QkeLe34z4ZAaPMt3wE-gcU-VoqYTGxz-K3Le2VaZ0r3j_z6bOInsv0yngC_cD1dCXMyQJWnWjQ`
    31  	rsaSignedTokenWithKid          = `eyJhbGciOiJSUzI1NiIsImtpZCI6ImZvb2JhciJ9.eyJpc3MiOiJpc3N1ZXIiLCJzY29wZXMiOlsiczEiLCJzMiJdLCJzdWIiOiJzdWJqZWN0In0.RxZhTRfPDb6UJ58FwvC89GgJGC8lAO04tz5iLlBpIJsyPZB0X_UgXSj0SGVFm2jbP_i-ZVH4HFC2fMB1n-so9CnCOpunWwhYNdgF6ewQJ0ADTWwfDGsK12UOmyT2naaZN8ZUBF8cgPtOgdWqQjk2Ng9QFRJxlUuKYczBp7vjWvgX8WMwQcaA-eK7HtguR4e9c4FMbeFK8Soc4jCsVTjIKdSn9SErc42gFu65NI1hZ3OPe_T7AZqdDjCkJpoiJ65GdD_qvGkVndJSEcMp3riXQpAy0JbctVkYecdFaGidbxHRrdcQYHtKn-XGMCh2uoBKleUr1fTMiyCGPQQesy3xHw`
    32  	invalidPayloadSignedToken      = `eyJhbGciOiJIUzI1NiJ9.aW52YWxpZC1wYXlsb2Fk.ScBKKm18jcaMLGYDNRUqB5gVMRZl4DM6dh3ShcxeNgY`
    33  	invalidPartsSignedToken        = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiaXNzIjoiaXNzdWVyIiwic2NvcGVzIjpbInMxIiwiczIiXX0`
    34  	hmacEncryptedToken             = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..NZrU98U4QNO0y-u6.HSq5CvlmkUT1BPqLGZ4.1-zuiZ4RbHrTTUoA8Dvfhg`
    35  	rsaEncryptedToken              = `eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.IvkVHHiI8JwwavvTR80xGjYvkzubMrZ-TDDx8k8SNJMEylfFfNUc7F2rC3WAABF_xmJ3SW2A6on-S6EAG97k0RsjqHHNqZuaFpDvjeuLqZFfYKzI45aCtkGG4C2ij2GbeySqJ784CcvFJPUWJ-6VPN2Ho2nhefUSqig0jE2IvOKy1ywTj_VBVBxF_dyXFnXwxPKGUQr3apxrWeRJfDh2Cf8YPBlLiRznjfBfwgePB1jP7WCZNwItj10L7hsT_YWEx01XJcbxHaXFLwKyVzwWaDhreFyaWMRbGqEfqVuOT34zfmhLDhQlgLLwkXrvYqX90NsQ9Ftg0LLIfRMbsfdgug.BFy2Tj1RZN8yq2Lk-kMiZQ.9Z0eOyPiv5cEzmXh64RlAQ36Uvz0WpZgqRcc2_69zHTmUOv0Vnl1I6ks8sTraUEvukAilolNBjBj47s0b4b-Og.VM8-eJg5ZsqnTqs0LtGX_Q`
    36  	invalidPayloadEncryptedToken   = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..T4jCS4Yyw1GCH0aW.y4gFaMITdBs_QZM8RKrL.6MPyk1cMVaOJFoNGlEuaRQ`
    37  	invalidPartsEncryptedToken     = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..NZrU98U4QNO0y-u6.HSq5CvlmkUT1BPqLGZ4`
    38  	signedAndEncryptedToken        = `eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiY3R5IjoiSldUIn0.icnR7M1HSgMDaUnJhfzT5nLmT0eRPeNsKPkioNcyq9TZsm-LgbE7wZkNFGfQqYwvbmrZ3UpOhNkrq4n2KN3N1dtjH9TVxzfMxz2OMh0dRWUNMi58EMadhmIpH3PLyyaeDyd0dyHpOIRPFTAoOdn2GoO_flV5CvPMhgdVKYB3h3vQW-ZZDu4cOZwXAjTuThdoUZCNWFhJhXyj-PrKLyVpX6rE1o4X05IS8008SLZyx-PZlsUPyLs6CJi7Z4PzZRzOJTV00a-7UOi-fBKBZV5V8eRpWuzJ673pMALlRCBzrRin-JeEA_QnAejtMAHG7RSGP60easQN4I-0jLTQNNNynw.oFrO-5ZgRrnWmbkPsbyMiQ.BVaWUzlrdfhe0otPJpb3DGoDCT6-BOmN_Pgq5NOqVFYIAwG5pM4pf7TaiPUJeQLf0phbLgpT4RfJ20Zhwfc2MH5unCqc8TZEP2dOrYRhb8o-X57x6IQppIDbjK2i_CAWf3yF5JUB7qRqOizpKZTh3HFTVEglY3WF8tAJ8KpnatTUmwcnqlyjdBFvYu4usiyvc_u9wNbXx5-lFt0slQYleHQMUirBprKyswIBjMoFJEe7kDvU_MCKI4NI9_fSfWJpaUdNxQEvRYR1PV4ZQdwBY0X9u2n2QH5iVQMrmgmQ5hPbWxwRv1-7jXBMPBpGeFQZHeEtSwif1_Umwyt8cDyRChb3OM7XQ3eY0UJRrbmvhcLWIcMp8FpblDaBinbjD6qIVXZVmaAdIbi2a_HblfoeL3-UABb82AAxOqQcAFjDEDTR2TFalDXSwgPZrAaQ_Mql3eFe9r2y0UVkgG7XYF4ik8sSK48CkZPUvkZFr-K9QMq-RZLzT3Zw0edxNaKgje27S26H9qClh6CCr9nk38AZZ76_Xz7f-Fil5xI0Dq95UzvwW__U3JJWE6OVUVx_RVJgdOJn8_B7hluckwBLUblscA.83pPXNnH0sKgHvFboiJVDA`
    39  	invalidSignedAndEncryptedToken = `eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.QKYu3DkFEXBUa2U0Sgtm-e44BMuaFVbMu2T-GB3qEGONrmOuaB5BtNCvBUnuj6HR0v6u-tvawToRSzExQQLFTvPcLiQR8iclWirqAFUqLrg8kRU3qIRLkmErYeGIfCML1jq9ofKg0DI5-YrU5RSyUg9cwfXKEx8KNwFcjeVeDZwWEACdU8xBnQp57rNfr0Tj-dPnGKID7LU5ZV0vhK90FpEG7UqOeSHFmvONQyz6Ca-ZkE8X2swqGad-q5xl8f9pApdFqHzADox5OlgtxPkr-Khkm6WGfvf1K_e-iW5LYtvWIAjNByft2TexsNcYpdAO2oNAgh2nkhoohl-zCWU-og.UAU65JWKqvHZ_Z0V-xLyjQ.M6sQ4lAzKFelSmL6C6uoK00rB8IFCAK-eJ0iByGhtg8eYtmSBFsP_oUySfKPtxcPRkQ7YxnEX5D-DOo20wCV7il2Be9No__0R6_5heISOMXcKmKP3D6pFusaPisNGOgLw8SKXBuVpe20PvOJ9RgOXRKucSR2UMINXtqIn9RdxbKOlBBmMJhnX4TeQ00fRILng2sMbUHsWExSthQODHGx6VcwLFp-Aqmsnv2q2KkLpA8sEm48AHHFQXSGtlVGVgWKi3dOQYUnDJW4P64Xxr1Uq3yT7w_dRwK4BA7l3Biecj5dwkKrFMJ_RaCt-ED_R15zpxg6PmnXeeJnif58Fai40ZWOsGvLZNYwL1jbi-TrsargpdUQedfzuTk8Na2NkCzFNg2BYXVDHJ_WAX1daVyhvunaURwAlBatAcmnOGxWebwV1xQoQ7iHg6ZGohCannn_pqGwJlMHMgnCcnCIhwfj9uL9Ejz_TVceZNMlT1KvLRafVfxGhkp48bdnd8OcXmjT9pQzZUB3OqrstWKhbItZ1xMpy6dZ54ldWvtTTyQ4tQJaVWgXERUM1erDT6Ypyl15-fumOB9MRcgMG3NDblKowA.P9WTBITvVUgrLjX6bS0opQ`
    40  )
    41  
    42  type customClaims struct {
    43  	Scopes []string `json:"scopes,omitempty"`
    44  }
    45  
    46  func TestGetClaimsWithoutVerification(t *testing.T) {
    47  	tok, err := ParseSigned(hmacSignedToken)
    48  	if assert.NoError(t, err, "Error parsing signed token.") {
    49  		c := &Claims{}
    50  		c2 := &customClaims{}
    51  
    52  		err := tok.UnsafeClaimsWithoutVerification(c, c2)
    53  		if err != nil {
    54  			t.Errorf("Error not expected: %s", err)
    55  		}
    56  		assert.Equal(t, "subject", c.Subject)
    57  		assert.Equal(t, "issuer", c.Issuer)
    58  		assert.Equal(t, []string{"s1", "s2"}, c2.Scopes)
    59  
    60  	}
    61  	tok, err = ParseEncrypted(hmacEncryptedToken)
    62  	if assert.NoError(t, err, "Error parsing encrypted token.") {
    63  		c := Claims{}
    64  		err := tok.UnsafeClaimsWithoutVerification(c)
    65  		if err == nil {
    66  			t.Errorf("Error expected")
    67  		}
    68  	}
    69  }
    70  
    71  func TestDecodeTokenWithJWKS(t *testing.T) {
    72  	jwks := &jose.JSONWebKeySet{
    73  		Keys: []jose.JSONWebKey{
    74  			{
    75  				KeyID: "foobar",
    76  				Key:   &testPrivRSAKey1.PublicKey,
    77  			},
    78  		},
    79  	}
    80  
    81  	tok, err := ParseSigned(rsaSignedTokenWithKid)
    82  	if assert.NoError(t, err, "Error parsing signed token.") {
    83  		cl := make(map[string]interface{})
    84  		expected := map[string]interface{}{
    85  			"sub":    "subject",
    86  			"iss":    "issuer",
    87  			"scopes": []interface{}{"s1", "s2"},
    88  		}
    89  
    90  		if assert.NoError(t, tok.Claims(jwks, &cl)) {
    91  			assert.Equal(t, expected, cl)
    92  		}
    93  
    94  		cl = make(map[string]interface{})
    95  		if assert.NoError(t, tok.Claims(*jwks, &cl)) {
    96  			assert.Equal(t, expected, cl)
    97  		}
    98  	}
    99  }
   100  
   101  func TestDecodeToken(t *testing.T) {
   102  	tok, err := ParseSigned(hmacSignedToken)
   103  	if assert.NoError(t, err, "Error parsing signed token.") {
   104  		c := &Claims{}
   105  		c2 := &customClaims{}
   106  		if assert.NoError(t, tok.Claims(sharedKey, c, c2)) {
   107  			assert.Equal(t, "subject", c.Subject)
   108  			assert.Equal(t, "issuer", c.Issuer)
   109  			assert.Equal(t, []string{"s1", "s2"}, c2.Scopes)
   110  		}
   111  	}
   112  	assert.EqualError(t, tok.Claims([]byte("invalid-secret")), "go-jose/go-jose: error in cryptographic primitive")
   113  
   114  	tok2, err := ParseSigned(rsaSignedToken)
   115  	if assert.NoError(t, err, "Error parsing encrypted token.") {
   116  		c := make(map[string]interface{})
   117  		if assert.NoError(t, tok2.Claims(&testPrivRSAKey1.PublicKey, &c)) {
   118  			assert.Equal(t, map[string]interface{}{
   119  				"sub":    "subject",
   120  				"iss":    "issuer",
   121  				"scopes": []interface{}{"s1", "s2"},
   122  			}, c)
   123  		}
   124  	}
   125  	assert.EqualError(t, tok.Claims(&testPrivRSAKey2.PublicKey), "go-jose/go-jose: error in cryptographic primitive")
   126  
   127  	tok3, err := ParseSigned(invalidPayloadSignedToken)
   128  	if assert.NoError(t, err, "Error parsing signed token.") {
   129  		assert.Error(t, tok3.Claims(sharedKey, &Claims{}), "Expected unmarshaling claims to fail.")
   130  	}
   131  
   132  	_, err = ParseSigned(invalidPartsSignedToken)
   133  	assert.EqualError(t, err, "go-jose/go-jose: compact JWS format must have three parts")
   134  
   135  	tok4, err := ParseEncrypted(hmacEncryptedToken)
   136  	if assert.NoError(t, err, "Error parsing encrypted token.") {
   137  		c := Claims{}
   138  		if assert.NoError(t, tok4.Claims(sharedEncryptionKey, &c)) {
   139  			assert.Equal(t, "foo", c.Subject)
   140  		}
   141  	}
   142  	assert.EqualError(t, tok4.Claims([]byte("invalid-secret-key")), "go-jose/go-jose: error in cryptographic primitive")
   143  
   144  	tok5, err := ParseEncrypted(rsaEncryptedToken)
   145  	if assert.NoError(t, err, "Error parsing encrypted token.") {
   146  		c := make(map[string]interface{})
   147  		if assert.NoError(t, tok5.Claims(testPrivRSAKey1, &c)) {
   148  			assert.Equal(t, map[string]interface{}{
   149  				"sub":    "subject",
   150  				"iss":    "issuer",
   151  				"scopes": []interface{}{"s1", "s2"},
   152  			}, c)
   153  		}
   154  	}
   155  	assert.EqualError(t, tok5.Claims(testPrivRSAKey2), "go-jose/go-jose: error in cryptographic primitive")
   156  
   157  	tok6, err := ParseEncrypted(invalidPayloadEncryptedToken)
   158  	if assert.NoError(t, err, "Error parsing encrypted token.") {
   159  		assert.Error(t, tok6.Claims(sharedEncryptionKey, &Claims{}))
   160  	}
   161  
   162  	_, err = ParseEncrypted(invalidPartsEncryptedToken)
   163  	assert.EqualError(t, err, "go-jose/go-jose: compact JWE format must have five parts")
   164  
   165  	tok7, err := ParseSignedAndEncrypted(signedAndEncryptedToken)
   166  	if assert.NoError(t, err, "Error parsing signed-then-encrypted token.") {
   167  		c := make(map[string]interface{})
   168  		if nested, err := tok7.Decrypt(testPrivRSAKey1); assert.NoError(t, err) {
   169  			assert.NoError(t, nested.Claims(testPrivRSAKey1.Public(), &c))
   170  			assert.Equal(t, map[string]interface{}{
   171  				"sub":    "subject",
   172  				"iss":    "issuer",
   173  				"scopes": []interface{}{"s1", "s2"},
   174  			}, c)
   175  			assert.EqualError(t, nested.Claims(testPrivRSAKey2.Public()), "go-jose/go-jose: error in cryptographic primitive")
   176  		}
   177  	}
   178  	_, err = tok7.Decrypt(testPrivRSAKey2)
   179  	assert.EqualError(t, err, "go-jose/go-jose: error in cryptographic primitive")
   180  
   181  	_, err = ParseSignedAndEncrypted(invalidSignedAndEncryptedToken)
   182  	assert.EqualError(t, err, "go-jose/go-jose/jwt: expected content type to be JWT (cty header)")
   183  }
   184  
   185  func TestTamperedJWT(t *testing.T) {
   186  	key := []byte("1234567890123456")
   187  
   188  	sig, _ := jose.NewEncrypter(
   189  		jose.A128GCM,
   190  		jose.Recipient{Algorithm: jose.DIRECT, Key: key},
   191  		(&jose.EncrypterOptions{}).WithType("JWT"))
   192  
   193  	cl := Claims{
   194  		Subject: "foo",
   195  		Issuer:  "bar",
   196  	}
   197  
   198  	raw, _ := Encrypted(sig).Claims(cl).CompactSerialize()
   199  
   200  	// Modify with valid base64 junk
   201  	r := strings.Split(raw, ".")
   202  	r[2] = "b3RoZXJ0aGluZw"
   203  	raw = strings.Join(r, ".")
   204  
   205  	tok, _ := ParseEncrypted(raw)
   206  
   207  	cl = Claims{}
   208  	err := tok.Claims(key, &cl)
   209  	if err == nil {
   210  		t.Error("Claims() on invalid token should fail")
   211  	}
   212  }
   213  
   214  func BenchmarkDecodeSignedToken(b *testing.B) {
   215  	for i := 0; i < b.N; i++ {
   216  		ParseSigned(hmacSignedToken)
   217  	}
   218  }
   219  
   220  func BenchmarkDecodeEncryptedHMACToken(b *testing.B) {
   221  	for i := 0; i < b.N; i++ {
   222  		ParseEncrypted(hmacEncryptedToken)
   223  	}
   224  }
   225  

View as plain text