mirror of
https://github.com/mickael-kerjean/filestash
synced 2025-12-06 08:22:24 +01:00
feature (plg_authenticate_local): local source of user
This commit is contained in:
parent
bc68bf50fe
commit
799ba868c3
9 changed files with 298 additions and 176 deletions
269
server/plugin/plg_authenticate_local/auth.go
Normal file
269
server/plugin/plg_authenticate_local/auth.go
Normal file
|
|
@ -0,0 +1,269 @@
|
||||||
|
package plg_authenticate_local
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"image/png"
|
||||||
|
"net/http"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
. "github.com/mickael-kerjean/filestash/server/common"
|
||||||
|
|
||||||
|
"github.com/pquerna/otp/totp"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SimpleAuth struct{}
|
||||||
|
|
||||||
|
func (this SimpleAuth) Setup() Form {
|
||||||
|
nUsers := 0
|
||||||
|
aUsers := 0
|
||||||
|
if users, err := getUsers(); err == nil {
|
||||||
|
nUsers = len(users)
|
||||||
|
for i := range users {
|
||||||
|
if users[i].Disabled == false {
|
||||||
|
aUsers += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Form{
|
||||||
|
Elmnts: []FormElement{
|
||||||
|
{
|
||||||
|
Name: "banner",
|
||||||
|
Type: "hidden",
|
||||||
|
Description: fmt.Sprintf(`Manage your team members and their account permissions by visiting [/admin/simple-user-management](/admin/simple-user-management).
|
||||||
|
<pre>
|
||||||
|
STATS:
|
||||||
|
┌─────────────┐ ┌──────────────┐
|
||||||
|
│ TOTAL USERS │ │ ACTIVE USERS │
|
||||||
|
| %.4d │ | %.4d │
|
||||||
|
└─────────────┘ └──────────────┘
|
||||||
|
|
||||||
|
MANAGEMENT GUI: <a href="/admin/simple-user-management">/admin/simple-user-management</a>
|
||||||
|
EMAIL SERVER : %t
|
||||||
|
</pre>`, nUsers, aUsers, isEmailSetup()),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "type",
|
||||||
|
Type: "hidden",
|
||||||
|
Value: "local",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "mfa",
|
||||||
|
Type: "select",
|
||||||
|
Default: "",
|
||||||
|
Opts: []string{"", "TOTP"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "notification_subject",
|
||||||
|
Type: "text",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "notification_body",
|
||||||
|
Type: "long_text",
|
||||||
|
Placeholder: `Hello,
|
||||||
|
|
||||||
|
Your account to Filestash was created by an administrator. You can access
|
||||||
|
it via http://demo.filestash.app.
|
||||||
|
|
||||||
|
Your password is: {{ .password }}
|
||||||
|
The roles assigned to you: {{ .role }}
|
||||||
|
|
||||||
|
Cheers!`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "db",
|
||||||
|
Type: "hidden",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this SimpleAuth) EntryPoint(idpParams map[string]string, req *http.Request, res http.ResponseWriter) error {
|
||||||
|
getFlash := func() string {
|
||||||
|
c, err := req.Cookie("flash")
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
http.SetCookie(res, &http.Cookie{
|
||||||
|
Name: "flash",
|
||||||
|
MaxAge: -1,
|
||||||
|
Path: "/",
|
||||||
|
})
|
||||||
|
return fmt.Sprintf(`<p class="flash">%s</p>`, c.Value)
|
||||||
|
}
|
||||||
|
res.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
res.WriteHeader(http.StatusOK)
|
||||||
|
if c, err := req.Cookie("mfa"); err == nil && c.Value != "" {
|
||||||
|
user := withMFA(User{}, c.Value)
|
||||||
|
key, err := totp.Generate(totp.GenerateOpts{
|
||||||
|
Issuer: Config.Get("general.name").String(),
|
||||||
|
AccountName: user.Email,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
img, err := key.Image(200, 200)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = png.Encode(&buf, img); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
template.Must(template.New("app").Parse(Page(`
|
||||||
|
<form action="`+WithBase("/api/session/auth/")+`" method="post" class="component_middleware">
|
||||||
|
{{ if eq .User.MFA "" }}
|
||||||
|
<style>
|
||||||
|
#init { padding: 20px 20px 10px 20px; text-align: center; background: rgba(0,0,0,0.1); border-radius: 10px; margin-top: -10vh; margin-bottom: 20px; }
|
||||||
|
#init input { background: transparent; margin-bottom: 0; text-align: center; }
|
||||||
|
</style>
|
||||||
|
<div id="init">
|
||||||
|
<img src="data:image/png;base64,{{ .QRCode }}" />
|
||||||
|
<input type="text" name="mfa" value="{{ .MFASecret }}" readonly />
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
<label>
|
||||||
|
<input type="text" name="code" placeholder="code" />
|
||||||
|
</label>
|
||||||
|
<input type="hidden" name="session" value="{{ .Session }}" />
|
||||||
|
<button>SUBMIT</button>
|
||||||
|
`+getFlash()+`
|
||||||
|
<style>
|
||||||
|
form { padding-top: 10vh; }
|
||||||
|
</style>
|
||||||
|
</form>
|
||||||
|
`))).Execute(res, struct {
|
||||||
|
User User
|
||||||
|
Session string
|
||||||
|
MFASecret string
|
||||||
|
QRCode string
|
||||||
|
}{
|
||||||
|
User: user,
|
||||||
|
Session: c.Value,
|
||||||
|
MFASecret: key.Secret(),
|
||||||
|
QRCode: base64.StdEncoding.EncodeToString(buf.Bytes()),
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
res.Write([]byte(Page(`
|
||||||
|
<form action="` + WithBase("/api/session/auth/") + `" method="post" class="component_middleware">
|
||||||
|
<label>
|
||||||
|
<input type="text" name="email" value="" placeholder="Email" />
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="password" name="password" value="" placeholder="Password" />
|
||||||
|
</label>
|
||||||
|
<button>CONNECT</button>
|
||||||
|
` + getFlash() + `
|
||||||
|
<style>
|
||||||
|
.flash{ color: #f26d6d; font-weight: bold; }
|
||||||
|
form { padding-top: 10vh; }
|
||||||
|
</style>
|
||||||
|
</form>`)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this SimpleAuth) Callback(formData map[string]string, idpParams map[string]string, res http.ResponseWriter) (map[string]string, error) {
|
||||||
|
users, err := getUsers()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
requestedUser := withMFA(User{
|
||||||
|
Email: formData["email"],
|
||||||
|
Password: formData["password"],
|
||||||
|
}, formData["session"])
|
||||||
|
requestedUser.Code = formData["code"]
|
||||||
|
for i := range users {
|
||||||
|
if users[i].Email != requestedUser.Email {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err = bcrypt.CompareHashAndPassword([]byte(users[i].Password), []byte(requestedUser.Password)); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if users[i].Disabled == true {
|
||||||
|
http.SetCookie(res, &http.Cookie{
|
||||||
|
Name: "flash",
|
||||||
|
Value: "Account is disabled",
|
||||||
|
MaxAge: 1,
|
||||||
|
Path: "/",
|
||||||
|
})
|
||||||
|
Log.Warning("plg_authentication_simple::auth action=authenticate email=%s err=disabled", users[i].Email)
|
||||||
|
return nil, ErrAuthenticationFailed
|
||||||
|
}
|
||||||
|
if idpParams["mfa"] == "TOTP" {
|
||||||
|
shouldSaveMFAKey := false
|
||||||
|
if users[i].MFA == "" {
|
||||||
|
users[i].MFA = formData["mfa"]
|
||||||
|
shouldSaveMFAKey = true
|
||||||
|
}
|
||||||
|
if totp.Validate(requestedUser.Code, users[i].MFA) == false {
|
||||||
|
requestedUser.MFA = users[i].MFA
|
||||||
|
http.SetCookie(res, &http.Cookie{
|
||||||
|
Name: "mfa",
|
||||||
|
Value: requestedUser.EncryptedString(),
|
||||||
|
MaxAge: 1,
|
||||||
|
})
|
||||||
|
return nil, ErrAuthenticationFailed
|
||||||
|
}
|
||||||
|
if shouldSaveMFAKey {
|
||||||
|
saveUsers(users)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
session := map[string]string{
|
||||||
|
"user": requestedUser.Email,
|
||||||
|
"password": requestedUser.Password,
|
||||||
|
"bcrypt": users[i].Password,
|
||||||
|
"role": users[i].Role,
|
||||||
|
}
|
||||||
|
s := ""
|
||||||
|
for k, v := range session {
|
||||||
|
if k == "password" || k == "bcrypt" {
|
||||||
|
v = "*****"
|
||||||
|
}
|
||||||
|
s += fmt.Sprintf("%s[%s] ", k, v)
|
||||||
|
}
|
||||||
|
Log.Debug("IDP Attributes => %s", s)
|
||||||
|
return session, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
http.SetCookie(res, &http.Cookie{
|
||||||
|
Name: "flash",
|
||||||
|
Value: "Invalid username or password",
|
||||||
|
MaxAge: 1,
|
||||||
|
Path: "/",
|
||||||
|
})
|
||||||
|
return nil, ErrAuthenticationFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
func withMFA(user User, session string) User {
|
||||||
|
if session == "" {
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
data, err := DecryptString(SECRET_KEY_DERIVATE_FOR_USER, session)
|
||||||
|
if err != nil {
|
||||||
|
return User{}
|
||||||
|
}
|
||||||
|
var u User
|
||||||
|
if err = json.Unmarshal([]byte(data), &u); err != nil {
|
||||||
|
return User{}
|
||||||
|
}
|
||||||
|
user.Email = u.Email
|
||||||
|
user.Password = u.Password
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user User) EncryptedString() string {
|
||||||
|
b, err := json.Marshal(user)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
d, err := EncryptString(SECRET_KEY_DERIVATE_FOR_USER, string(b))
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package plg_authenticate_simple
|
package plg_authenticate_local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
@ -8,7 +8,7 @@ import (
|
||||||
|
|
||||||
func getPluginData() (pluginConfig, error) {
|
func getPluginData() (pluginConfig, error) {
|
||||||
var cfg pluginConfig
|
var cfg pluginConfig
|
||||||
if Config.Get("middleware.identity_provider.type").String() != "simple" {
|
if Config.Get("middleware.identity_provider.type").String() != "local" {
|
||||||
Log.Warning("plg_authenticate_simple::disable msg=middleware_is_not_enabled")
|
Log.Warning("plg_authenticate_simple::disable msg=middleware_is_not_enabled")
|
||||||
return cfg, ErrMissingDependency
|
return cfg, ErrMissingDependency
|
||||||
}
|
}
|
||||||
|
|
@ -30,7 +30,7 @@ func getPluginData() (pluginConfig, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func savePluginData(cfg pluginConfig) error {
|
func savePluginData(cfg pluginConfig) error {
|
||||||
if Config.Get("middleware.identity_provider.type").String() != "simple" {
|
if Config.Get("middleware.identity_provider.type").String() != "local" {
|
||||||
Log.Warning("plg_authenticate_simple::disable msg=middleware_is_not_enabled")
|
Log.Warning("plg_authenticate_simple::disable msg=middleware_is_not_enabled")
|
||||||
return ErrMissingDependency
|
return ErrMissingDependency
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package plg_authenticate_simple
|
package plg_authenticate_local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package plg_authenticate_simple
|
package plg_authenticate_local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
@ -9,22 +9,8 @@ import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
type User struct {
|
|
||||||
Email string `json:"email"`
|
|
||||||
Password string `json:"password"`
|
|
||||||
Role string `json:"role"`
|
|
||||||
Disabled bool `json:"disabled"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type pluginConfig struct {
|
|
||||||
DB string `json:"db"`
|
|
||||||
Users []User `json:"-"`
|
|
||||||
Subject string `json:"notification_subject"`
|
|
||||||
Body string `json:"notification_body"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Hooks.Register.AuthenticationMiddleware("simple", SimpleAuth{})
|
Hooks.Register.AuthenticationMiddleware("local", SimpleAuth{})
|
||||||
Hooks.Register.HttpEndpoint(func(r *mux.Router, app *App) error {
|
Hooks.Register.HttpEndpoint(func(r *mux.Router, app *App) error {
|
||||||
r.Handle("/admin/simple-user-management", http.RedirectHandler("/admin/api/simple-user-management", http.StatusSeeOther)).Methods("GET")
|
r.Handle("/admin/simple-user-management", http.RedirectHandler("/admin/api/simple-user-management", http.StatusSeeOther)).Methods("GET")
|
||||||
r.HandleFunc("/admin/api/simple-user-management", middleware.NewMiddlewareChain(
|
r.HandleFunc("/admin/api/simple-user-management", middleware.NewMiddlewareChain(
|
||||||
|
|
@ -35,3 +21,21 @@ func init() {
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Role string `json:"role"`
|
||||||
|
Disabled bool `json:"disabled"`
|
||||||
|
|
||||||
|
Code string `json:"-"`
|
||||||
|
MFA string `json:"mfa"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type pluginConfig struct {
|
||||||
|
DB string `json:"db"`
|
||||||
|
MFA string `json:"mfa"`
|
||||||
|
Users []User `json:"-"`
|
||||||
|
Subject string `json:"notification_subject"`
|
||||||
|
Body string `json:"notification_body"`
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package plg_authenticate_simple
|
package plg_authenticate_local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package plg_authenticate_simple
|
package plg_authenticate_local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sort"
|
"sort"
|
||||||
|
|
@ -53,7 +53,8 @@ func updateUser(user User) error {
|
||||||
}
|
}
|
||||||
user.Password = string(p)
|
user.Password = string(p)
|
||||||
}
|
}
|
||||||
users[i] = user
|
users[i].Disabled = user.Disabled
|
||||||
|
users[i].Role = user.Role
|
||||||
return saveUsers(users)
|
return saveUsers(users)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package plg_authenticate_simple
|
package plg_authenticate_local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -1,152 +0,0 @@
|
||||||
package plg_authenticate_simple
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
. "github.com/mickael-kerjean/filestash/server/common"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SimpleAuth struct{}
|
|
||||||
|
|
||||||
func (this SimpleAuth) Setup() Form {
|
|
||||||
nUsers := 0
|
|
||||||
aUsers := 0
|
|
||||||
if users, err := getUsers(); err == nil {
|
|
||||||
nUsers = len(users)
|
|
||||||
for i := range users {
|
|
||||||
if users[i].Disabled == false {
|
|
||||||
aUsers += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Form{
|
|
||||||
Elmnts: []FormElement{
|
|
||||||
{
|
|
||||||
Name: "banner",
|
|
||||||
Type: "hidden",
|
|
||||||
Description: fmt.Sprintf(`Manage your team members and their account permissions by visiting [/admin/simple-user-management](/admin/simple-user-management).
|
|
||||||
<pre>
|
|
||||||
STATS:
|
|
||||||
┌─────────────┐ ┌──────────────┐
|
|
||||||
│ TOTAL USERS │ │ ACTIVE USERS │
|
|
||||||
| %.4d │ | %.4d │
|
|
||||||
└─────────────┘ └──────────────┘
|
|
||||||
|
|
||||||
MANAGEMENT GUI: <a href="/admin/simple-user-management">/admin/simple-user-management</a>
|
|
||||||
EMAIL SERVER : %t
|
|
||||||
</pre>`, nUsers, aUsers, isEmailSetup()),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "type",
|
|
||||||
Type: "hidden",
|
|
||||||
Value: "simple",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "notification_subject",
|
|
||||||
Type: "text",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "notification_body",
|
|
||||||
Type: "long_text",
|
|
||||||
Placeholder: `Hello,
|
|
||||||
|
|
||||||
Your account to Filestash was created by an administrator. You can access
|
|
||||||
it via http://demo.filestash.app.
|
|
||||||
|
|
||||||
Your password is: {{ .password }}
|
|
||||||
The roles assigned to you: {{ .role }}
|
|
||||||
|
|
||||||
Cheers!`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "db",
|
|
||||||
Type: "hidden",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this SimpleAuth) EntryPoint(idpParams map[string]string, req *http.Request, res http.ResponseWriter) error {
|
|
||||||
getFlash := func() string {
|
|
||||||
c, err := req.Cookie("flash")
|
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
http.SetCookie(res, &http.Cookie{
|
|
||||||
Name: "flash",
|
|
||||||
MaxAge: -1,
|
|
||||||
Path: "/",
|
|
||||||
})
|
|
||||||
return fmt.Sprintf(`<p class="flash">%s</p>`, c.Value)
|
|
||||||
}
|
|
||||||
res.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
||||||
res.WriteHeader(http.StatusOK)
|
|
||||||
res.Write([]byte(Page(`
|
|
||||||
<form action="` + WithBase("/api/session/auth/") + `" method="post" class="component_middleware">
|
|
||||||
<label>
|
|
||||||
<input type="text" name="email" value="" placeholder="Email" />
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<input type="password" name="password" value="" placeholder="Password" />
|
|
||||||
</label>
|
|
||||||
<button>CONNECT</button>
|
|
||||||
` + getFlash() + `
|
|
||||||
<style>
|
|
||||||
.flash{ color: #f26d6d; font-weight: bold; }
|
|
||||||
form { padding-top: 10vh; }
|
|
||||||
</style>
|
|
||||||
</form>`)))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this SimpleAuth) Callback(formData map[string]string, idpParams map[string]string, res http.ResponseWriter) (map[string]string, error) {
|
|
||||||
users, err := getUsers()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for i := range users {
|
|
||||||
if users[i].Email != formData["email"] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err = bcrypt.CompareHashAndPassword([]byte(users[i].Password), []byte(formData["password"])); err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if users[i].Disabled == true {
|
|
||||||
http.SetCookie(res, &http.Cookie{
|
|
||||||
Name: "flash",
|
|
||||||
Value: "Account is disabled",
|
|
||||||
MaxAge: 1,
|
|
||||||
Path: "/",
|
|
||||||
})
|
|
||||||
Log.Warning("plg_authentication_simple::auth action=authenticate email=%s err=disabled", users[i].Email)
|
|
||||||
return nil, ErrAuthenticationFailed
|
|
||||||
}
|
|
||||||
session := map[string]string{
|
|
||||||
"user": formData["email"],
|
|
||||||
"password": formData["password"],
|
|
||||||
"bcrypt": users[i].Password,
|
|
||||||
"role": users[i].Role,
|
|
||||||
}
|
|
||||||
s := ""
|
|
||||||
for k, v := range session {
|
|
||||||
if k == "password" || k == "bcrypt" {
|
|
||||||
v = "*****"
|
|
||||||
}
|
|
||||||
s += fmt.Sprintf("%s[%s] ", k, v)
|
|
||||||
}
|
|
||||||
Log.Debug("IDP Attributes => %s", s)
|
|
||||||
return session, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
http.SetCookie(res, &http.Cookie{
|
|
||||||
Name: "flash",
|
|
||||||
Value: "Inalid username or password",
|
|
||||||
MaxAge: 1,
|
|
||||||
Path: "/",
|
|
||||||
})
|
|
||||||
return nil, ErrAuthenticationFailed
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue