2020-02-12 16:39:57 +00:00
|
|
|
package core
|
2020-02-10 09:23:10 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/base64"
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
|
2021-03-30 19:40:02 +00:00
|
|
|
"github.com/cadmium-im/zirconium-go/core/models"
|
|
|
|
|
2020-02-10 09:23:10 +00:00
|
|
|
"github.com/dgrijalva/jwt-go"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
SigningKeyBytesAmount = 4096
|
|
|
|
TokenExpireTimeDuration = 24 * time.Hour
|
|
|
|
)
|
|
|
|
|
|
|
|
type AuthManager struct {
|
|
|
|
signingKey string // For now it is random bytes string represented in Base64
|
|
|
|
}
|
|
|
|
|
|
|
|
type JWTCustomClaims struct {
|
2021-03-30 19:40:02 +00:00
|
|
|
EntityID []*models.EntityID `json:"entityID"`
|
|
|
|
DeviceID string `json:"deviceID"`
|
2020-02-10 09:23:10 +00:00
|
|
|
jwt.StandardClaims
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewAuthManager() (*AuthManager, error) {
|
|
|
|
am := &AuthManager{}
|
|
|
|
bytes, err := GenRandomBytes(SigningKeyBytesAmount)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
am.signingKey = base64.RawStdEncoding.EncodeToString(bytes)
|
|
|
|
return am, nil
|
|
|
|
}
|
|
|
|
|
2021-03-30 19:40:02 +00:00
|
|
|
func (am *AuthManager) CreateNewToken(entityID *models.EntityID, deviceID string, tokenExpireTimeDuration time.Duration) (string, error) {
|
2020-02-10 09:23:10 +00:00
|
|
|
timeNow := time.Now()
|
|
|
|
expiringTime := timeNow.Add(tokenExpireTimeDuration)
|
2021-03-30 19:40:02 +00:00
|
|
|
|
2020-02-10 09:23:10 +00:00
|
|
|
claims := JWTCustomClaims{
|
2021-03-30 19:40:02 +00:00
|
|
|
[]*models.EntityID{entityID},
|
2020-02-10 09:23:10 +00:00
|
|
|
deviceID,
|
|
|
|
jwt.StandardClaims{
|
|
|
|
ExpiresAt: time.Date(
|
|
|
|
expiringTime.Year(),
|
|
|
|
expiringTime.Month(),
|
|
|
|
expiringTime.Day(),
|
|
|
|
expiringTime.Hour(),
|
|
|
|
expiringTime.Minute(),
|
|
|
|
expiringTime.Second(),
|
|
|
|
expiringTime.Nanosecond(),
|
|
|
|
time.UTC,
|
|
|
|
).Unix(),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
|
|
|
tokenString, err := token.SignedString(am.signingKey)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return tokenString, nil
|
|
|
|
}
|
|
|
|
|
2021-03-30 19:40:02 +00:00
|
|
|
func (am *AuthManager) ValidateToken(tokenString string) (*JWTCustomClaims, error) {
|
2020-02-10 09:23:10 +00:00
|
|
|
token, err := jwt.ParseWithClaims(tokenString, &JWTCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
|
|
|
|
// Don't forget to validate the alg is what you expect:
|
|
|
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
2021-03-30 19:40:02 +00:00
|
|
|
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
2020-02-10 09:23:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
|
|
|
|
return []byte(am.signingKey), nil
|
|
|
|
})
|
|
|
|
|
2021-03-30 19:40:02 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-02-10 09:23:10 +00:00
|
|
|
if claims, ok := token.Claims.(*JWTCustomClaims); ok && token.Valid {
|
2021-03-30 19:40:02 +00:00
|
|
|
return claims, nil
|
2020-02-10 09:23:10 +00:00
|
|
|
}
|
2021-03-30 19:40:02 +00:00
|
|
|
return nil, err
|
2020-02-10 09:23:10 +00:00
|
|
|
}
|