github.com/simpleiot/simpleiot@v0.18.3/api/key.go (about)

     1  package api
     2  
     3  import (
     4  	"net/http"
     5  	"strings"
     6  	"time"
     7  
     8  	"github.com/golang-jwt/jwt/v4"
     9  )
    10  
    11  // Authorizer defines a mechanism needed to authorize stuff
    12  type Authorizer interface {
    13  	NewToken(id string) (string, error)
    14  	Valid(req *http.Request) (bool, string)
    15  }
    16  
    17  // AlwaysValid is used to disable authentication
    18  type AlwaysValid struct{}
    19  
    20  // NewToken stub
    21  func (AlwaysValid) NewToken(_ string) (string, error) { return "valid", nil }
    22  
    23  // Valid stub
    24  func (AlwaysValid) Valid(*http.Request) (bool, string) {
    25  	return true, ""
    26  }
    27  
    28  // Key provides a key for signing authentication tokens.
    29  type Key struct {
    30  	bytes []byte
    31  }
    32  
    33  // NewKey returns a new Key of the given size.
    34  func NewKey(bytes []byte) (key Key, err error) {
    35  	key.bytes = bytes
    36  	return
    37  }
    38  
    39  // NewToken returns a new authentication token signed by the Key.
    40  func (k Key) NewToken(userID string) (string, error) {
    41  	// FIXME Id is probably not the proper place to put the userid
    42  	// but works for now
    43  	claims := jwt.StandardClaims{
    44  		ExpiresAt: time.Now().Add(168 * time.Hour).Unix(),
    45  		Issuer:    "simpleiot",
    46  		Id:        userID,
    47  	}
    48  	return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).
    49  		SignedString(k.bytes)
    50  }
    51  
    52  // ValidToken returns whether the given string
    53  // is an authentication token signed by the Key.
    54  func (k Key) ValidToken(str string) (bool, string) {
    55  	token, err := jwt.Parse(str, k.keyFunc)
    56  	if err != nil {
    57  		return false, ""
    58  	}
    59  	claims, ok := token.Claims.(jwt.MapClaims)
    60  	if !ok {
    61  		return false, ""
    62  	}
    63  	userID, ok := claims["jti"].(string)
    64  	if !ok {
    65  		return false, ""
    66  	}
    67  	return (err == nil &&
    68  		token.Method.Alg() == "HS256" &&
    69  		token.Valid), userID
    70  }
    71  
    72  // Valid returns whether the given request
    73  // bears an authorization token signed by the Key.
    74  func (k Key) Valid(req *http.Request) (bool, string) {
    75  	fields := strings.Fields(req.Header.Get("Authorization"))
    76  	if len(fields) < 2 {
    77  		return false, ""
    78  	}
    79  	if fields[0] != "Bearer" {
    80  		return false, ""
    81  	}
    82  
    83  	valid, userID := k.ValidToken(fields[1])
    84  	return valid, userID
    85  }
    86  
    87  func (k Key) keyFunc(*jwt.Token) (interface{}, error) {
    88  	return k.bytes, nil
    89  }