gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

auth.go (2804B)


      1 // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
      2 // Use of this source code is governed by a MIT style
      3 // license that can be found in the LICENSE file.
      4 
      5 package gin
      6 
      7 import (
      8 	"crypto/subtle"
      9 	"encoding/base64"
     10 	"net/http"
     11 	"strconv"
     12 
     13 	"github.com/gin-gonic/gin/internal/bytesconv"
     14 )
     15 
     16 // AuthUserKey is the cookie name for user credential in basic auth.
     17 const AuthUserKey = "user"
     18 
     19 // Accounts defines a key/value for user/pass list of authorized logins.
     20 type Accounts map[string]string
     21 
     22 type authPair struct {
     23 	value string
     24 	user  string
     25 }
     26 
     27 type authPairs []authPair
     28 
     29 func (a authPairs) searchCredential(authValue string) (string, bool) {
     30 	if authValue == "" {
     31 		return "", false
     32 	}
     33 	for _, pair := range a {
     34 		if subtle.ConstantTimeCompare(bytesconv.StringToBytes(pair.value), bytesconv.StringToBytes(authValue)) == 1 {
     35 			return pair.user, true
     36 		}
     37 	}
     38 	return "", false
     39 }
     40 
     41 // BasicAuthForRealm returns a Basic HTTP Authorization middleware. It takes as arguments a map[string]string where
     42 // the key is the user name and the value is the password, as well as the name of the Realm.
     43 // If the realm is empty, "Authorization Required" will be used by default.
     44 // (see http://tools.ietf.org/html/rfc2617#section-1.2)
     45 func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {
     46 	if realm == "" {
     47 		realm = "Authorization Required"
     48 	}
     49 	realm = "Basic realm=" + strconv.Quote(realm)
     50 	pairs := processAccounts(accounts)
     51 	return func(c *Context) {
     52 		// Search user in the slice of allowed credentials
     53 		user, found := pairs.searchCredential(c.requestHeader("Authorization"))
     54 		if !found {
     55 			// Credentials doesn't match, we return 401 and abort handlers chain.
     56 			c.Header("WWW-Authenticate", realm)
     57 			c.AbortWithStatus(http.StatusUnauthorized)
     58 			return
     59 		}
     60 
     61 		// The user credentials was found, set user's id to key AuthUserKey in this context, the user's id can be read later using
     62 		// c.MustGet(gin.AuthUserKey).
     63 		c.Set(AuthUserKey, user)
     64 	}
     65 }
     66 
     67 // BasicAuth returns a Basic HTTP Authorization middleware. It takes as argument a map[string]string where
     68 // the key is the user name and the value is the password.
     69 func BasicAuth(accounts Accounts) HandlerFunc {
     70 	return BasicAuthForRealm(accounts, "")
     71 }
     72 
     73 func processAccounts(accounts Accounts) authPairs {
     74 	length := len(accounts)
     75 	assert1(length > 0, "Empty list of authorized credentials")
     76 	pairs := make(authPairs, 0, length)
     77 	for user, password := range accounts {
     78 		assert1(user != "", "User can not be empty")
     79 		value := authorizationHeader(user, password)
     80 		pairs = append(pairs, authPair{
     81 			value: value,
     82 			user:  user,
     83 		})
     84 	}
     85 	return pairs
     86 }
     87 
     88 func authorizationHeader(user, password string) string {
     89 	base := user + ":" + password
     90 	return "Basic " + base64.StdEncoding.EncodeToString(bytesconv.StringToBytes(base))
     91 }