Codebase list golang-github-go-kit-kit / 8c6ad4e
Basic Auth: optimize memory allocation. Dmitry Salakhov 6 years ago
2 changed file(s) with 23 addition(s) and 30 deletion(s). Raw diff Collapse all Expand all
0 `package auth/basic` provides a basic auth middleware [Mozilla article](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication)
0 `package auth/basic` provides a Basic Authentication middleware [Mozilla article](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication).
11
22 ## Usage
33
1212 )
1313 ```
1414
15 For AuthMiddleware to be able to pick up Authentication header from a http request we need to pass it through the context with something like ```httptransport.ServerBefore(httptransport.PopulateRequestContext)```
15 For AuthMiddleware to be able to pick up the Authentication header from a HTTP request we need to pass it through the context with something like ```httptransport.ServerBefore(httptransport.PopulateRequestContext)```.
00 package basic
11
22 import (
3 "bytes"
34 "context"
45 "crypto/sha256"
56 "crypto/subtle"
1213 httptransport "github.com/go-kit/kit/transport/http"
1314 )
1415
15 // AuthError represents generic Authorization error
16 // AuthError represents an authoriation error.
1617 type AuthError struct {
1718 Realm string
1819 }
1920
20 // StatusCode is an implemntation of StatusCoder interface in go-kit/http
21 // StatusCode is an iimplementation of the StatusCoder interface in go-kit/http.
2122 func (AuthError) StatusCode() int {
2223 return http.StatusUnauthorized
2324 }
2425
25 // Error is an implemntation of Error interface
26 // Error is an implementation of the Error interface.
2627 func (AuthError) Error() string {
2728 return http.StatusText(http.StatusUnauthorized)
2829 }
2930
30 // Headers is an implemntation of Headerer interface in go-kit/http
31 // Headers is an implemntation of the Headerer interface in go-kit/http.
3132 func (e AuthError) Headers() http.Header {
3233 return http.Header{
3334 "Content-Type": []string{"text/plain; charset=utf-8"},
3536 "WWW-Authenticate": []string{fmt.Sprintf(`Basic realm=%q`, e.Realm)}}
3637 }
3738
38 func credsAreValid(givenUser, givenPass, requiredUser, requiredPass string) bool {
39 // Equalize lengths of supplied and required credentials
40 // by hashing them
41 givenUserBytes := sha256.Sum256([]byte(givenUser))
42 givenPassBytes := sha256.Sum256([]byte(givenPass))
43 requiredUserBytes := sha256.Sum256([]byte(requiredUser))
44 requiredPassBytes := sha256.Sum256([]byte(requiredPass))
45
46 // Compare the supplied credentials to those set in our options
47 if subtle.ConstantTimeCompare(givenUserBytes[:], requiredUserBytes[:]) == 1 &&
48 subtle.ConstantTimeCompare(givenPassBytes[:], requiredPassBytes[:]) == 1 {
49 return true
50 }
51
52 return false
53 }
54
5539 // parseBasicAuth parses an HTTP Basic Authentication string.
56 // "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true).
57 func parseBasicAuth(auth string) (username, password string, ok bool) {
40 // "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ([]byte("Aladdin"), []byte("open sesame"), true).
41 func parseBasicAuth(auth string) (username, password []byte, ok bool) {
5842 const prefix = "Basic "
5943 if !strings.HasPrefix(auth, prefix) {
6044 return
6347 if err != nil {
6448 return
6549 }
66 cs := string(c)
67 s := strings.IndexByte(cs, ':')
50
51 s := bytes.IndexByte(c, ':')
6852 if s < 0 {
6953 return
7054 }
71 return cs[:s], cs[s+1:], true
55 return c[:s], c[s+1:], true
7256 }
7357
74 // AuthMiddleware returns a Basic Authentication middleware for a particular user and password
58 // AuthMiddleware returns a Basic Authentication middleware for a particular user and password.
7559 func AuthMiddleware(requiredUser, requiredPassword, realm string) endpoint.Middleware {
60 requiredUserBytes := sha256.Sum256([]byte(requiredUser))
61 requiredPassBytes := sha256.Sum256([]byte(requiredPassword))
62
7663 return func(next endpoint.Endpoint) endpoint.Endpoint {
7764 return func(ctx context.Context, request interface{}) (interface{}, error) {
7865 auth := ctx.Value(httptransport.ContextKeyRequestAuthorization).(string)
8168 return nil, AuthError{realm}
8269 }
8370
84 if !credsAreValid(givenUser, givenPass, requiredUser, requiredPassword) {
71 // Equalize lengths of supplied and required credentials by hashing them.
72 givenUserBytes := sha256.Sum256(givenUser)
73 givenPassBytes := sha256.Sum256(givenPass)
74
75 // Compare the supplied credentials to those set in our options.
76 if subtle.ConstantTimeCompare(givenUserBytes[:], requiredUserBytes[:]) == 0 ||
77 subtle.ConstantTimeCompare(givenPassBytes[:], requiredPassBytes[:]) == 0 {
8578 return nil, AuthError{realm}
8679 }
8780