154 lines
4.0 KiB
Go
154 lines
4.0 KiB
Go
package auth
|
|
|
|
import (
|
|
"crypto/rsa"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"time"
|
|
|
|
"github.com/pquerna/ffjson/ffjson"
|
|
|
|
"strings"
|
|
|
|
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
|
|
"bitbucket.org/nemt/nemt-portal-api/infra/config"
|
|
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
|
|
jwt "github.com/dgrijalva/jwt-go"
|
|
"github.com/labstack/echo"
|
|
)
|
|
|
|
const (
|
|
// AppKeyHeaderName is the header name for application keys
|
|
AppKeyHeaderName = "App"
|
|
// AppTokenHeaderName is the header name for application token
|
|
AppTokenHeaderName = "Token"
|
|
// TokenExpiration is the auth token default expiration time
|
|
TokenExpiration = 24 * time.Hour
|
|
)
|
|
|
|
var (
|
|
// TokenSigningMethod is the auth token signing algorithm
|
|
TokenSigningMethod = jwt.SigningMethodRS256
|
|
)
|
|
|
|
// GetAppKeyFromContext returns the application key from request header
|
|
func GetAppKeyFromContext(ctx echo.Context) (appKey string, err error) {
|
|
appKey = ctx.Request().Header.Get(AppKeyHeaderName)
|
|
|
|
if strings.TrimSpace(appKey) == "" {
|
|
return "", errors.NewNotAuthorizedError("Application key not found")
|
|
}
|
|
|
|
return appKey, nil
|
|
}
|
|
|
|
// ValidateAppKey validates the presence and validity of App key
|
|
func ValidateAppKey(ctx echo.Context, cfg *config.Config) (err error) {
|
|
appKey, err := GetAppKeyFromContext(ctx)
|
|
if err != nil {
|
|
return errors.Wrap(err)
|
|
}
|
|
|
|
if appKey != cfg.HTTP.Auth.AppKey {
|
|
return errors.NewNotAuthorizedError("Invalid API Key")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetCertPrivateKey returns the private key for the token authentication certificate
|
|
func GetCertPrivateKey(path string) (pk *rsa.PrivateKey, err error) {
|
|
data, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err)
|
|
}
|
|
|
|
pk, err = jwt.ParseRSAPrivateKeyFromPEM(data)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err)
|
|
}
|
|
|
|
return pk, nil
|
|
}
|
|
|
|
// GetCertPublicKey returns the public key for the token authentication certificate
|
|
func GetCertPublicKey(path string) (pk *rsa.PublicKey, err error) {
|
|
privateKey, err := GetCertPrivateKey(path)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err)
|
|
}
|
|
|
|
return &privateKey.PublicKey, nil
|
|
}
|
|
|
|
// GenerateToken creates a token based on certificate
|
|
func GenerateToken(cfg *config.Config, data interface{}) (tokenString string, err error) {
|
|
key, _ := GetCertPrivateKey(cfg.HTTP.Auth.CertificatePath)
|
|
|
|
claims := jwt.MapClaims{
|
|
"iat": time.Now().Unix(),
|
|
"exp": time.Now().Add(TokenExpiration).Unix(),
|
|
"iss": "BDC",
|
|
"sub": "NEMT",
|
|
"data": data,
|
|
}
|
|
|
|
token := jwt.NewWithClaims(TokenSigningMethod, claims)
|
|
tokenString, err = token.SignedString(key)
|
|
if err != nil {
|
|
return tokenString, errors.Wrap(err)
|
|
}
|
|
|
|
return tokenString, nil
|
|
}
|
|
|
|
func GetTokenDetail(ctx echo.Context, cfg *config.Config) (interface{}, error) {
|
|
key, _ := GetCertPublicKey(cfg.HTTP.Auth.CertificatePath)
|
|
|
|
tokenString := ctx.Request().Header.Get("Token")
|
|
tokenString = strings.Replace(tokenString, "Bearer ", "", -1)
|
|
|
|
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
|
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
|
|
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
|
}
|
|
return key, nil
|
|
})
|
|
|
|
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
|
return claims["data"], nil
|
|
} else {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
func GetUserDetail(ctx echo.Context, cfg *config.Config) (viewmodel.User, error) {
|
|
key, _ := GetCertPublicKey(cfg.HTTP.Auth.CertificatePath)
|
|
|
|
tokenString := ctx.Request().Header.Get("Token")
|
|
tokenString = strings.Replace(tokenString, "Bearer ", "", -1)
|
|
|
|
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
|
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
|
|
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
|
}
|
|
return key, nil
|
|
})
|
|
if err != nil {
|
|
return viewmodel.User{}, err
|
|
}
|
|
|
|
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
|
byteData, _ := ffjson.Marshal(claims["data"])
|
|
user := viewmodel.User{}
|
|
err = ffjson.Unmarshal(byteData, &user)
|
|
if err != nil {
|
|
return viewmodel.User{}, err
|
|
} else {
|
|
return user, nil
|
|
}
|
|
} else {
|
|
return viewmodel.User{}, err
|
|
}
|
|
}
|