github.com/mendersoftware/go-lib-micro@v0.0.0-20240304135804-e8e39c59b148/identity/token_test.go (about) 1 // Copyright 2023 Northern.tech AS 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package identity 15 16 import ( 17 "encoding/base64" 18 "encoding/json" 19 "net/http" 20 "testing" 21 22 "github.com/stretchr/testify/assert" 23 ) 24 25 func boolPtr(val bool) *bool { 26 return &val 27 } 28 29 func makeClaimsFull(sub, tenant, plan string, device, user, trial bool) string { 30 claim := struct { 31 Subject string `json:"sub,omitempty"` 32 Tenant string `json:"mender.tenant,omitempty"` 33 Device *bool `json:"mender.device,omitempty"` 34 User *bool `json:"mender.user,omitempty"` 35 Plan string `json:"mender.plan,omitempty"` 36 Trial bool `json:"mender.trial"` 37 }{ 38 Subject: sub, 39 Tenant: tenant, 40 Plan: plan, 41 Trial: trial, 42 } 43 44 if device { 45 claim.Device = boolPtr(true) 46 } 47 if user { 48 claim.User = boolPtr(true) 49 } 50 data, _ := json.Marshal(&claim) 51 rawclaim := base64.RawURLEncoding.EncodeToString(data) 52 return rawclaim 53 } 54 55 func makeClaimsPart(sub, tenant, plan string) string { 56 return makeClaimsFull(sub, tenant, plan, false, false, false) 57 } 58 59 func TestExtractIdentity(t *testing.T) { 60 _, err := ExtractIdentity("foo") 61 assert.Error(t, err) 62 63 _, err = ExtractIdentity("foo.bar") 64 assert.Error(t, err) 65 66 _, err = ExtractIdentity("foo.bar.baz") 67 assert.Error(t, err) 68 69 // should fail, token is malformed, missing header & signature 70 rawclaims := makeClaimsPart("foobar", "", "") 71 _, err = ExtractIdentity(rawclaims) 72 assert.Error(t, err) 73 74 // correct case 75 idata, err := ExtractIdentity("foo." + rawclaims + ".bar") 76 assert.NoError(t, err) 77 assert.Equal(t, Identity{Subject: "foobar"}, idata) 78 79 // missing subject 80 enc := base64.RawURLEncoding.EncodeToString([]byte(`{"iss": "Mender"}`)) 81 _, err = ExtractIdentity("foo." + enc + ".bar") 82 assert.Error(t, err) 83 84 // bad subject 85 enc = base64.RawURLEncoding.EncodeToString([]byte(`{"sub": 1}`)) 86 _, err = ExtractIdentity("foo." + enc + ".bar") 87 assert.Error(t, err) 88 89 enc = base64.RawURLEncoding.EncodeToString([]byte(`{"sub": "123", "mender.device": true}`)) 90 idata, err = ExtractIdentity("foo." + enc + ".bar") 91 assert.NoError(t, err) 92 assert.Equal(t, Identity{Subject: "123", IsDevice: true}, idata) 93 94 enc = base64.RawURLEncoding.EncodeToString([]byte(`{"sub": "123", "mender.user": true}`)) 95 idata, err = ExtractIdentity("foo." + enc + ".bar") 96 assert.NoError(t, err) 97 assert.Equal(t, Identity{Subject: "123", IsUser: true}, idata) 98 99 enc = base64.RawURLEncoding.EncodeToString([]byte(`{"sub": "123", "mender.user": {"garbage": 2}}`)) 100 _, err = ExtractIdentity("foo." + enc + ".bar") 101 assert.Error(t, err) 102 assert.Contains(t, err.Error(), "failed to decode JSON JWT claims") 103 104 _, err = ExtractIdentity("foo.barrr.baz") 105 assert.Error(t, err) 106 assert.Contains(t, err.Error(), "failed to decode base64 JWT claims") 107 108 rawclaims = makeClaimsFull("foobar", "", "", false, true, true) 109 idata, err = ExtractIdentity("foo." + rawclaims + ".bar") 110 assert.NoError(t, err) 111 assert.Equal(t, Identity{Subject: "foobar", IsUser: true, Trial: true}, idata) 112 } 113 114 func TestExtractIdentityFromHeaders(t *testing.T) { 115 r := &http.Request{ 116 Header: http.Header{}, 117 } 118 _, err := ExtractJWTFromHeader(r) 119 assert.Error(t, err) 120 121 r.Header.Set("Authorization", "Basic foobar") 122 _, err = ExtractJWTFromHeader(r) 123 assert.Error(t, err) 124 125 r.Header.Set("Authorization", "Bearer") 126 _, err = ExtractJWTFromHeader(r) 127 assert.Error(t, err) 128 129 // correct cate 130 rawclaims := makeClaimsPart("foobar", "", "") 131 actualJWT := "foo." + rawclaims + ".bar" 132 r.Header.Set("Authorization", "Bearer "+actualJWT) 133 jwt, err := ExtractJWTFromHeader(r) 134 assert.NoError(t, err) 135 assert.Equal(t, actualJWT, jwt) 136 137 r.Header.Del("Authorization") 138 r.AddCookie(&http.Cookie{ 139 Name: "JWT", 140 Value: "foo." + rawclaims + ".bar", 141 }) 142 jwt, err = ExtractJWTFromHeader(r) 143 assert.NoError(t, err) 144 assert.Equal(t, actualJWT, jwt) 145 }