This repository has been archived by the owner on Mar 7, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathauth.go
182 lines (147 loc) · 4.56 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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
package main
import (
"context"
"database/sql"
// "crypto/rsa"
// "encoding/gob"
// "github.com/gorilla/mux"
// "github.com/gorilla/securecookie"
"github.com/gorilla/sessions"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/bcrypt"
// "html/template"
"net/http"
// "time"
)
// ImpfUser is a row from the users table. It has the username and hash of the
// password the user uses to login, aswell as the default values to populate
// new calls
type ImpfUser struct {
Password string `db:"password"`
Username string `db:"username"`
}
type contextKey string
var (
// contextKeyAuthtoken = contextKey("auth-token")
contextKeyCurrentUser = contextKey("current_user")
)
func authenticateUser(user, pass string) bool {
log.Debugf("Trying to authenticate: user[%s] pass[%s]\n", user, pass)
// Create an instance of `Credentials` to store the credentials from DB
storedCreds := ImpfUser{}
// Get the existing entry present in the database for the given username
if err := bridge.db.Get(&storedCreds, "SELECT * FROM users WHERE username=$1", user); err != nil {
if err == sql.ErrNoRows {
log.Debug(err)
// User not present in the database
} else {
// Something else went wrong. This should not happen, log and return
log.Error(err)
}
return false
}
// Compare the stored hashed password, with the received and hashed
// password
if err := bcrypt.CompareHashAndPassword([]byte(storedCreds.Password), []byte(pass)); err != nil {
return false
}
// Session is valid
log.Infof("Successfull authentication for user: [%s]\n", user)
return true
}
// reads the form values, checks them and creates a session
func authHandler(w http.ResponseWriter, r *http.Request) {
session, err := store.Get(r, "impf-auth")
if err != nil {
log.Warn("Could not retrieve session cookie from store")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Read form values of login page
inputUsername := r.FormValue("user")
inputPassword := r.FormValue("pass")
if !authenticateUser(inputUsername, inputPassword) {
session.AddFlash("Ungültige Zugangsdaten")
err = session.Save(r, w)
if err != nil {
log.Warn("Error saving session cookie: ", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/forbidden", http.StatusFound)
return
}
user := &User{
Username: inputUsername,
Authenticated: true,
}
session.Values["user"] = user
err = session.Save(r, w)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/auth/call", http.StatusFound)
}
// Serve login page
func loginHandler(w http.ResponseWriter, r *http.Request) {
if err := templates.ExecuteTemplate(w, "login.html", TmplData{}); err != nil {
log.Error(err)
}
}
// middlewareAuth prepended to all handlers to handle authentication
func middlewareAuth(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
session, err := store.Get(r, "impf-auth")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
user := getUser(session)
if auth := user.Authenticated; !auth {
session.AddFlash("Login notwendig!")
err = session.Save(r, w)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/forbidden", http.StatusFound)
return
}
// Session is valid. At this point the login is succesfull and this
// middleware has done it's job. Pass on to the next handler and
// record the login in the application log for good measure
log.Debugf("Login successful for user: [%v]\n", user)
ctx := context.WithValue(r.Context(), contextKeyCurrentUser, user.Username)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func forbiddenHandler(w http.ResponseWriter, r *http.Request) {
log.Warn("forbidden reached")
session, err := store.Get(r, "impf-auth")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Error("Error getting cookie: ", err)
return
}
err = session.Save(r, w)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Error("Error saving cookie", err)
return
}
tData := TmplData{AppMessages: []string{"Login Fehlgeschlagen"}}
if err := templates.ExecuteTemplate(w, "login.html", tData); err != nil {
log.Error(err)
}
}
// getUser returns a user from session s
// on error returns an empty user
func getUser(s *sessions.Session) User {
val := s.Values["user"]
user, ok := val.(User)
if !ok {
return User{Authenticated: false}
}
return user
}