github.com/nats-io/jwt/v2@v2.5.6/genericlaims.go (about)

     1  /*
     2   * Copyright 2018-2020 The NATS Authors
     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   */
    15  
    16  package jwt
    17  
    18  import (
    19  	"encoding/json"
    20  	"errors"
    21  	"strings"
    22  
    23  	"github.com/nats-io/nkeys"
    24  )
    25  
    26  // GenericClaims can be used to read a JWT as a map for any non-generic fields
    27  type GenericClaims struct {
    28  	ClaimsData
    29  	Data map[string]interface{} `json:"nats,omitempty"`
    30  }
    31  
    32  // NewGenericClaims creates a map-based Claims
    33  func NewGenericClaims(subject string) *GenericClaims {
    34  	if subject == "" {
    35  		return nil
    36  	}
    37  	c := GenericClaims{}
    38  	c.Subject = subject
    39  	c.Data = make(map[string]interface{})
    40  	return &c
    41  }
    42  
    43  // DecodeGeneric takes a JWT string and decodes it into a ClaimsData and map
    44  func DecodeGeneric(token string) (*GenericClaims, error) {
    45  	// must have 3 chunks
    46  	chunks := strings.Split(token, ".")
    47  	if len(chunks) != 3 {
    48  		return nil, errors.New("expected 3 chunks")
    49  	}
    50  
    51  	// header
    52  	header, err := parseHeaders(chunks[0])
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  	// claim
    57  	data, err := decodeString(chunks[1])
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  
    62  	gc := struct {
    63  		GenericClaims
    64  		GenericFields
    65  	}{}
    66  	if err := json.Unmarshal(data, &gc); err != nil {
    67  		return nil, err
    68  	}
    69  
    70  	// sig
    71  	sig, err := decodeString(chunks[2])
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  
    76  	if header.Algorithm == AlgorithmNkeyOld {
    77  		if !gc.verify(chunks[1], sig) {
    78  			return nil, errors.New("claim failed V1 signature verification")
    79  		}
    80  		if tp := gc.GenericFields.Type; tp != "" {
    81  			// the conversion needs to be from a string because
    82  			// on custom types the type is not going to be one of
    83  			// the constants
    84  			gc.GenericClaims.Data["type"] = string(tp)
    85  		}
    86  		if tp := gc.GenericFields.Tags; len(tp) != 0 {
    87  			gc.GenericClaims.Data["tags"] = tp
    88  		}
    89  
    90  	} else {
    91  		if !gc.verify(token[:len(chunks[0])+len(chunks[1])+1], sig) {
    92  			return nil, errors.New("claim failed V2 signature verification")
    93  		}
    94  	}
    95  	return &gc.GenericClaims, nil
    96  }
    97  
    98  // Claims returns the standard part of the generic claim
    99  func (gc *GenericClaims) Claims() *ClaimsData {
   100  	return &gc.ClaimsData
   101  }
   102  
   103  // Payload returns the custom part of the claims data
   104  func (gc *GenericClaims) Payload() interface{} {
   105  	return &gc.Data
   106  }
   107  
   108  // Encode takes a generic claims and creates a JWT string
   109  func (gc *GenericClaims) Encode(pair nkeys.KeyPair) (string, error) {
   110  	return gc.ClaimsData.encode(pair, gc)
   111  }
   112  
   113  // Validate checks the generic part of the claims data
   114  func (gc *GenericClaims) Validate(vr *ValidationResults) {
   115  	gc.ClaimsData.Validate(vr)
   116  }
   117  
   118  func (gc *GenericClaims) String() string {
   119  	return gc.ClaimsData.String(gc)
   120  }
   121  
   122  // ExpectedPrefixes returns the types allowed to encode a generic JWT, which is nil for all
   123  func (gc *GenericClaims) ExpectedPrefixes() []nkeys.PrefixByte {
   124  	return nil
   125  }
   126  
   127  func (gc *GenericClaims) ClaimType() ClaimType {
   128  	v, ok := gc.Data["type"]
   129  	if !ok {
   130  		v, ok = gc.Data["nats"]
   131  		if ok {
   132  			m, ok := v.(map[string]interface{})
   133  			if ok {
   134  				v = m["type"]
   135  			}
   136  		}
   137  	}
   138  
   139  	switch ct := v.(type) {
   140  	case string:
   141  		if IsGenericClaimType(ct) {
   142  			return GenericClaim
   143  		}
   144  		return ClaimType(ct)
   145  	case ClaimType:
   146  		return ct
   147  	default:
   148  		return ""
   149  	}
   150  }
   151  
   152  func (gc *GenericClaims) updateVersion() {
   153  	if gc.Data != nil {
   154  		// store as float as that is what decoding with json does too
   155  		gc.Data["version"] = float64(libVersion)
   156  	}
   157  }