github.com/apremalal/vamps-core@v1.0.1-0.20161221121535-d430b56ec174/controllers/token_service.go (about)

     1  package controllers
     2  
     3  import (
     4  	"bufio"
     5  	"crypto/rsa"
     6  	"crypto/x509"
     7  	"database/sql"
     8  	"encoding/pem"
     9  	"os"
    10  	"time"
    11  
    12  	"errors"
    13  
    14  	log "github.com/Sirupsen/logrus"
    15  	jwt "github.com/dgrijalva/jwt-go"
    16  	"github.com/vedicsoft/vamps-core/commons"
    17  	"github.com/vedicsoft/vamps-core/models"
    18  	"github.com/vedicsoft/vamps-core/redis"
    19  	"golang.org/x/crypto/bcrypt"
    20  )
    21  
    22  type JWTAuthenticationBackend struct {
    23  	privateKey *rsa.PrivateKey
    24  	PublicKey  *rsa.PublicKey
    25  }
    26  
    27  const (
    28  	expireOffset = 3600
    29  )
    30  
    31  var authBackendInstance *JWTAuthenticationBackend = nil
    32  
    33  func InitJWTAuthenticationEngine() *JWTAuthenticationBackend {
    34  	if authBackendInstance == nil {
    35  		authBackendInstance = &JWTAuthenticationBackend{
    36  			privateKey: getPrivateKey(),
    37  			PublicKey:  getPublicKey(),
    38  		}
    39  	}
    40  	return authBackendInstance
    41  }
    42  
    43  func (backend *JWTAuthenticationBackend) GenerateToken(user *models.SystemUser) (string, error) {
    44  	token := jwt.New(jwt.SigningMethodRS512)
    45  	i := commons.ServerConfigurations.JWTExpirationDelta
    46  	token.Claims["exp"] = time.Now().Add(time.Hour * time.Duration(i)).Unix()
    47  	token.Claims["iat"] = time.Now().Unix()
    48  	token.Claims["sub"] = user.Username
    49  	token.Claims["tenantid"] = user.TenantId
    50  	token.Claims["userid"] = getUserId(user)
    51  	scopes, err := getUserScopes(user)
    52  	if err != nil {
    53  		return "", errors.New("could not load user scopes stack trace: " + err.Error())
    54  	}
    55  	token.Claims["scopes"] = scopes
    56  	tokenString, err := token.SignedString(backend.privateKey)
    57  	if err != nil {
    58  		return "", errors.New("unable to sign the jwt stack trace: " + err.Error())
    59  	}
    60  	return tokenString, nil
    61  }
    62  
    63  func getUserId(user *models.SystemUser) int64 {
    64  	dbMap := commons.GetDBConnection(commons.PLATFORM_DB)
    65  	var userId sql.NullInt64
    66  	smtOut, err := dbMap.Db.Prepare("SELECT userid FROM vs_users WHERE username=? AND tenantid=?")
    67  	defer smtOut.Close()
    68  	err = smtOut.QueryRow(user.Username, user.TenantId).Scan(&userId)
    69  	if err != nil {
    70  		log.Debug("User authentication failed " + user.Username)
    71  		return -1
    72  	} else {
    73  		user.UserId = userId.Int64
    74  		return userId.Int64
    75  	}
    76  }
    77  
    78  func getUserScopes(user *models.SystemUser) ([]string, error) {
    79  	const GET_USER_ROLES string = `SELECT vs_roles.name from vs_roles WHERE vs_roles.roleid IN (SELECT
    80  								   vs_user_roles.roleid FROM vs_user_roles WHERE
    81  								   vs_user_roles.userid=?) AND vs_roles.type='system'`
    82  	var roles []string
    83  	dbMap := commons.GetDBConnection(commons.PLATFORM_DB)
    84  	var err error
    85  	_, err = dbMap.Select(&roles, GET_USER_ROLES, user.UserId)
    86  	if err != nil {
    87  		return roles, err
    88  	}
    89  	return roles, err
    90  }
    91  
    92  func (backend *JWTAuthenticationBackend) Authenticate(user *models.SystemUser) bool {
    93  	dbMap := commons.GetDBConnection(commons.PLATFORM_DB)
    94  	var hashedPassword sql.NullString
    95  	smtOut, err := dbMap.Db.Prepare("SELECT password FROM vs_users where username=? AND tenantid=? AND status='active'")
    96  	defer smtOut.Close()
    97  
    98  	err = smtOut.QueryRow(user.Username, user.TenantId).Scan(&hashedPassword)
    99  	if err == nil && hashedPassword.Valid {
   100  		if len(hashedPassword.String) > 0 {
   101  			err = bcrypt.CompareHashAndPassword([]byte(hashedPassword.String), []byte(user.Password))
   102  			if err == nil {
   103  				log.Debug("User authenticated successfully " + user.Username)
   104  				return true
   105  			}
   106  		}
   107  	} else {
   108  		log.Debug("User authentication failed for user " + user.Username)
   109  		return false
   110  	}
   111  	return false
   112  }
   113  
   114  func (backend *JWTAuthenticationBackend) getTokenRemainingValidity(timestamp interface{}) int {
   115  	if validity, ok := timestamp.(float64); ok {
   116  		tm := time.Unix(int64(validity), 0)
   117  		remainer := tm.Sub(time.Now())
   118  		if remainer > 0 {
   119  			return int(remainer.Seconds() + expireOffset)
   120  		}
   121  	}
   122  	return expireOffset
   123  }
   124  
   125  func (backend *JWTAuthenticationBackend) Logout(tokenString string, token *jwt.Token) error {
   126  	return redis.SetValue(tokenString, tokenString, backend.getTokenRemainingValidity(token.Claims["exp"]))
   127  }
   128  
   129  func (backend *JWTAuthenticationBackend) IsInBlacklist(token string) bool {
   130  	redisToken, err := redis.GetValue(token)
   131  	if err != nil {
   132  		log.Error("Error occourred while checking for black listed jwt :" + token + " stack :" + err.Error())
   133  	}
   134  	if redisToken == nil {
   135  		log.Debug("Token is not in the black list")
   136  		return false
   137  	}
   138  	log.Debug("Found a blacklisted token")
   139  	return true
   140  }
   141  
   142  func getPrivateKey() *rsa.PrivateKey {
   143  
   144  	privateKeyFile, err := os.Open(commons.ServerConfigurations.JWTPrivateKeyFile)
   145  	if err != nil {
   146  		panic(err)
   147  	}
   148  
   149  	pemfileinfo, _ := privateKeyFile.Stat()
   150  	var size int64 = pemfileinfo.Size()
   151  	pembytes := make([]byte, size)
   152  
   153  	buffer := bufio.NewReader(privateKeyFile)
   154  	_, err = buffer.Read(pembytes)
   155  
   156  	data, _ := pem.Decode([]byte(pembytes))
   157  
   158  	defer privateKeyFile.Close()
   159  
   160  	privateKeyImported, err := x509.ParsePKCS1PrivateKey(data.Bytes)
   161  
   162  	if err != nil {
   163  		panic(err)
   164  	}
   165  	return privateKeyImported
   166  }
   167  
   168  func getPublicKey() *rsa.PublicKey {
   169  	publicKeyFile, err := os.Open(commons.ServerConfigurations.JWTPublicKeyFile)
   170  	if err != nil {
   171  		panic(err)
   172  	}
   173  
   174  	pemfileinfo, _ := publicKeyFile.Stat()
   175  	var size int64 = pemfileinfo.Size()
   176  	pembytes := make([]byte, size)
   177  
   178  	buffer := bufio.NewReader(publicKeyFile)
   179  	_, err = buffer.Read(pembytes)
   180  
   181  	data, _ := pem.Decode([]byte(pembytes))
   182  
   183  	defer publicKeyFile.Close()
   184  
   185  	publicKeyImported, err := x509.ParsePKIXPublicKey(data.Bytes)
   186  
   187  	if err != nil {
   188  		panic(err)
   189  	}
   190  
   191  	rsaPub, ok := publicKeyImported.(*rsa.PublicKey)
   192  
   193  	if !ok {
   194  		panic(err)
   195  	}
   196  
   197  	return rsaPub
   198  }