Skip to content

Instantly share code, notes, and snippets.

@dahernan
Last active August 29, 2015 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dahernan/f7593c5b83073e99c0a2 to your computer and use it in GitHub Desktop.
Save dahernan/f7593c5b83073e99c0a2 to your computer and use it in GitHub Desktop.
Basic auth login route
// example for Minimal Auth
// it does not compile is just as a guide for rolling your own
// some code for login by http post
func (a *AuthRoute) Login(w http.ResponseWriter, req *http.Request) {
var authForm map[string]string
err := RequestToJsonObject(req, &authForm)
if err != nil {
Render().JSON(w, http.StatusUnauthorized, nil)
return
}
email := authForm["email"]
pass := authForm["password"]
userId, err := a.userStore.Login(email, pass)
if err != nil {
Render().JSON(w, http.StatusUnauthorized, "Username or Password Invalid")
log.Printf("INFO: Failed attempt to login '%s' with error '%v'\n", email, err)
return
}
log.Println("INFO: user login", email, userId)
token, err := jwt.GenerateJWTToken(userId)
if err != nil {
Render().JSON(w, http.StatusInternalServerError, "Error while Signing Token :S")
log.Printf("ERROR: Token Signing error: %v\n", err)
return
}
authredis.SetSessionToken(token, userId)
Render().JSON(w, http.StatusOK, map[string]string{"token": token})
}
// some code to validate the login in Redis
func (r *RedisRepository) Login(email, pass string) (string, error) {
id, err := r.UserByEmail(email)
if err != nil {
return "", err
}
userId := string(id)
if userId == "" {
return "", ErrUserNotFound
}
data, err := r.client.HMGet(userKey+userId, "Password", "Salt")
if err != nil {
return "", err
}
if string(data[0]) == "" {
return "", ErrUserNotFound
}
passStored := data[0]
salt := data[1]
hpass, err := HashPassword(pass, salt)
if err != nil {
return "", err
}
passOk := SecureCompare(hpass, passStored)
if !passOk {
return "", ErrWrongPassword
}
r.client.HSet(userKey+userId, "Lastlogin", strconv.FormatInt(time.Now().Unix(), 10))
log.Println("INFO: User Login", userId, email)
return userId, nil
}
// "golang.org/x/crypto/scrypt"
func HashPassword(pass string, salt []byte) ([]byte, error) {
return scrypt.Key([]byte(pass), salt, 16384, 8, 1, 32)
}
//"crypto/subtle"
func SecureCompare(given, actual []byte) bool {
return subtle.ConstantTimeCompare(given, actual) == 1
}
// auth middleware for negroni
func AuthMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
var userId, token string
var err error
auth := r.Header.Get("Authorization")
if auth == "" {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprintln(w, "Error while Validation Token!")
return
}
// API Auth "Basic "
if strings.HasPrefix(auth, "Basic ") {
userId, token, err = validateAPIToken(auth)
} else {
// Web Auth with JWT "Bearer "
userId, token, err = jwt.ValidateToken(r)
}
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprintln(w, err.Error())
log.Printf("ERROR: Token Validation Error: %+v\n", err.Error())
return
}
context.Set(r, TokenKey, token)
context.Set(r, UserKey, userId)
// gorilla context Clear
defer context.Clear(r)
next(w, r)
}
// Generate and Validate JWT with
// jwt "github.com/dgrijalva/jwt-go"
func GenerateJWTToken(userId string) (string, error) {
// create a signer for rsa 256
t := jwt.New(jwt.GetSigningMethod("RS256"))
// set claims
t.Claims["exp"] = time.Now().Add(time.Minute * 60).Unix()
t.Claims["iat"] = time.Now().Unix()
t.Claims["sub"] = userId
tokenString, err := t.SignedString([]byte(keys.Private))
return tokenString, err
}
func ValidateToken(r *http.Request) (string, string, error) {
token, err := jwt.ParseFromRequest(r, func(token *jwt.Token) (interface{}, error) {
return []byte(keys.Public), nil
})
if err != nil {
switch err.(type) {
case *jwt.ValidationError:
vErr := err.(*jwt.ValidationError)
switch vErr.Errors {
case jwt.ValidationErrorExpired:
log.Printf("ERROR: JWT Token Expired: %+v\n", vErr.Errors)
return "", "", ErrTokenExpired
default:
log.Printf("ERROR: JWT Token ValidationError: %+v\n", vErr.Errors)
return "", "", ErrTokenValidation
}
}
log.Printf("ERROR: Token parse error: %v\n", err)
return "", "", ErrTokenParse
}
if !token.Valid {
log.Printf("ERROR: Token Invalid trying to access: %v\n", err)
return "", "", ErrTokenInvalid
}
// otherwise is a valid token
userId := token.Claims["sub"].(string)
//log.Printf("INFO: user '%s' accesed with a Valid token", userId)
return userId, token.Raw, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment