mirror of https://github.com/portainer/portainer
67 lines
1.6 KiB
Go
67 lines
1.6 KiB
Go
package jwt
|
|
|
|
import (
|
|
"github.com/portainer/portainer"
|
|
|
|
"fmt"
|
|
"github.com/dgrijalva/jwt-go"
|
|
"github.com/gorilla/securecookie"
|
|
"time"
|
|
)
|
|
|
|
// Service represents a service for managing JWT tokens.
|
|
type Service struct {
|
|
secret []byte
|
|
}
|
|
|
|
type claims struct {
|
|
Username string `json:"username"`
|
|
jwt.StandardClaims
|
|
}
|
|
|
|
// NewService initializes a new service. It will generate a random key that will be used to sign JWT tokens.
|
|
func NewService() (*Service, error) {
|
|
secret := securecookie.GenerateRandomKey(32)
|
|
if secret == nil {
|
|
return nil, portainer.ErrSecretGeneration
|
|
}
|
|
service := &Service{
|
|
secret,
|
|
}
|
|
return service, nil
|
|
}
|
|
|
|
// GenerateToken generates a new JWT token.
|
|
func (service *Service) GenerateToken(data *portainer.TokenData) (string, error) {
|
|
expireToken := time.Now().Add(time.Hour * 8).Unix()
|
|
cl := claims{
|
|
data.Username,
|
|
jwt.StandardClaims{
|
|
ExpiresAt: expireToken,
|
|
},
|
|
}
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, cl)
|
|
|
|
signedToken, err := token.SignedString(service.secret)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return signedToken, nil
|
|
}
|
|
|
|
// VerifyToken parses a JWT token and verify its validity. It returns an error if token is invalid.
|
|
func (service *Service) VerifyToken(token string) error {
|
|
parsedToken, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
|
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
|
msg := fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
|
return nil, msg
|
|
}
|
|
return service.secret, nil
|
|
})
|
|
if err != nil || parsedToken == nil || !parsedToken.Valid {
|
|
return portainer.ErrInvalidJWTToken
|
|
}
|
|
return nil
|
|
}
|