-
Notifications
You must be signed in to change notification settings - Fork 47
/
auth.go
108 lines (87 loc) · 2.85 KB
/
auth.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package main
import (
"encoding/base64"
"fmt"
"log"
"strings"
scrypt "github.com/elithrar/simple-scrypt"
"github.com/fasthttp/router"
"github.com/valyala/fasthttp"
)
// basicAuth returns the username and password provided in the request's
// Authorization header, if the request uses HTTP Basic Authentication.
// See RFC 2617, Section 2.
func basicAuth(ctx *fasthttp.RequestCtx) (username, password string, ok bool) {
auth := ctx.Request.Header.Peek("Authorization")
if auth == nil {
return
}
return parseBasicAuth(string(auth))
}
// parseBasicAuth parses an HTTP Basic Authentication string.
// "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true).
func parseBasicAuth(auth string) (username, password string, ok bool) {
const prefix = "Basic "
if !strings.HasPrefix(auth, prefix) {
return
}
c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
if err != nil {
return
}
cs := string(c)
s := strings.IndexByte(cs, ':')
if s < 0 {
return
}
return cs[:s], cs[s+1:], true
}
// BasicAuth is the basic auth handler
func BasicAuth(h fasthttp.RequestHandler, requiredUser string, requiredPasswordHash []byte) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
// Get the Basic Authentication credentials
user, password, hasAuth := basicAuth(ctx)
// WARNING:
// DO NOT use plain-text passwords for real apps.
// A simple string comparison using == is vulnerable to a timing attack.
// Instead, use the hash comparison function found in your hash library.
// This example uses scrypt, which is a solid choice for secure hashing:
// go get -u github.com/elithrar/simple-scrypt
if hasAuth && user == requiredUser {
// Uses the parameters from the existing derived key. Return an error if they don't match.
err := scrypt.CompareHashAndPassword(requiredPasswordHash, []byte(password))
if err != nil {
// log error and request Basic Authentication again below.
log.Fatal(err)
} else {
// Delegate request to the given handle
h(ctx)
return
}
}
// Request Basic Authentication otherwise
ctx.Error(fasthttp.StatusMessage(fasthttp.StatusUnauthorized), fasthttp.StatusUnauthorized)
ctx.Response.Header.Set("WWW-Authenticate", "Basic realm=Restricted")
}
}
// Index is the index handler
func Index(ctx *fasthttp.RequestCtx) {
fmt.Fprint(ctx, "Not protected!\n")
}
// Protected is the Protected handler
func Protected(ctx *fasthttp.RequestCtx) {
fmt.Fprint(ctx, "Protected!\n")
}
func main() {
user := "gordon"
pass := "secret!"
// generate a hashed password from the password above:
hashedPassword, err := scrypt.GenerateFromPassword([]byte(pass), scrypt.DefaultParams)
if err != nil {
log.Fatal(err)
}
r := router.New()
r.GET("/", Index)
r.GET("/protected/", BasicAuth(Protected, user, hashedPassword))
log.Fatal(fasthttp.ListenAndServe(":8080", r.Handler))
}