github.com/mendersoftware/go-lib-micro@v0.0.0-20240304135804-e8e39c59b148/identity/token.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 "strings" 21 22 "github.com/mendersoftware/go-lib-micro/addons" 23 "github.com/pkg/errors" 24 ) 25 26 type Identity struct { 27 Subject string `json:"sub" valid:"required"` 28 Tenant string `json:"mender.tenant,omitempty"` 29 IsUser bool `json:"mender.user,omitempty"` 30 IsDevice bool `json:"mender.device,omitempty"` 31 Plan string `json:"mender.plan,omitempty"` 32 Addons []addons.Addon `json:"mender.addons,omitempty"` 33 Trial bool `json:"mender.trial"` 34 } 35 36 // ExtractJWTFromHeader inspect the Authorization header for a Bearer token and 37 // if not present looks for a "JWT" cookie. 38 func ExtractJWTFromHeader(r *http.Request) (jwt string, err error) { 39 auth := r.Header.Get("Authorization") 40 if auth == "" { 41 jwtCookie, err := r.Cookie("JWT") 42 if err != nil { 43 return "", errors.New("Authorization not present in header") 44 } 45 jwt = jwtCookie.Value 46 } else { 47 auths := strings.Split(auth, " ") 48 49 if len(auths) != 2 { 50 return "", errors.Errorf("malformed Authorization header") 51 } 52 53 if !strings.EqualFold(auths[0], "Bearer") { 54 return "", errors.Errorf("unknown Authorization method %s", auths[0]) 55 } 56 jwt = auths[1] 57 } 58 return jwt, nil 59 } 60 61 // Generate identity information from given JWT by extracting subject and tenant claims. 62 // Note that this function does not perform any form of token signature 63 // verification. 64 func ExtractIdentity(token string) (id Identity, err error) { 65 var ( 66 claims []byte 67 jwt []string 68 ) 69 jwt = strings.Split(token, ".") 70 if len(jwt) != 3 { 71 return id, errors.New("identity: incorrect token format") 72 } 73 claims, err = base64.RawURLEncoding.DecodeString(jwt[1]) 74 if err != nil { 75 return id, errors.Wrap(err, 76 "identity: failed to decode base64 JWT claims") 77 } 78 err = json.Unmarshal(claims, &id) 79 if err != nil { 80 return id, errors.Wrap(err, 81 "identity: failed to decode JSON JWT claims") 82 } 83 return id, id.Validate() 84 } 85 86 func (id Identity) Validate() error { 87 if id.Subject == "" { 88 return errors.New("identity: claim \"sub\" is required") 89 } 90 return nil 91 }