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 }