...

Source file src/github.com/gin-gonic/gin/auth.go

Documentation: github.com/gin-gonic/gin

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

View as plain text