Files
old-svijetlastrana/infra/auth/auth.go
2018-04-25 13:16:36 +02:00

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
}
}