-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
handler_firstfactor.go
133 lines (105 loc) · 4.28 KB
/
handler_firstfactor.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
package handlers
import (
"fmt"
"net/url"
"time"
"github.com/clems4ever/authelia/regulation"
"github.com/clems4ever/authelia/session"
"github.com/clems4ever/authelia/authentication"
"github.com/clems4ever/authelia/authorization"
"github.com/clems4ever/authelia/middlewares"
)
// FirstFactorPost is the handler performing the first factory.
func FirstFactorPost(ctx *middlewares.AutheliaCtx) {
bodyJSON := firstFactorRequestBody{}
err := ctx.ParseBody(&bodyJSON)
if err != nil {
ctx.Error(err, authenticationFailedMessage)
return
}
bannedUntil, err := ctx.Providers.Regulator.Regulate(bodyJSON.Username)
if err == regulation.ErrUserIsBanned {
ctx.Error(fmt.Errorf("User %s is banned until %s", bodyJSON.Username, bannedUntil), userBannedMessage)
return
} else if err != nil {
ctx.Error(fmt.Errorf("Unable to regulate authentication: %s", err), authenticationFailedMessage)
return
}
userPasswordOk, err := ctx.Providers.UserProvider.CheckUserPassword(bodyJSON.Username, bodyJSON.Password)
if err != nil {
ctx.Error(fmt.Errorf("Error while checking password for user %s: %s", bodyJSON.Username, err.Error()), authenticationFailedMessage)
return
}
ctx.Logger.Debugf("Mark authentication attempt made by user %s", bodyJSON.Username)
// Mark the authentication attempt and whether it was successful.
err = ctx.Providers.Regulator.Mark(bodyJSON.Username, userPasswordOk)
if err != nil {
ctx.Error(fmt.Errorf("Unable to mark authentication: %s", err), authenticationFailedMessage)
return
}
if !userPasswordOk {
ctx.Error(fmt.Errorf("Credentials are wrong for user %s", bodyJSON.Username), authenticationFailedMessage)
return
}
ctx.Logger.Debugf("Credentials validation of user %s is ok", bodyJSON.Username)
// Reset all values from previous session before regenerating the cookie.
err = ctx.SaveSession(session.NewDefaultUserSession())
if err != nil {
ctx.Error(fmt.Errorf("Unable to reset the session for user %s: %s", bodyJSON.Username, err), authenticationFailedMessage)
return
}
err = ctx.Providers.SessionProvider.RegenerateSession(ctx.RequestCtx)
if err != nil {
ctx.Error(fmt.Errorf("Unable to regenerate session for user %s: %s", bodyJSON.Username, err), authenticationFailedMessage)
return
}
// and avoid the cookie to expire if "Remember me" was ticked.
if *bodyJSON.KeepMeLoggedIn {
err = ctx.Providers.SessionProvider.UpdateExpiration(ctx.RequestCtx, time.Duration(0))
if err != nil {
ctx.Error(fmt.Errorf("Unable to update expiration timer for user %s: %s", bodyJSON.Username, err), authenticationFailedMessage)
return
}
}
// Get the details of the given user from the user provider.
userDetails, err := ctx.Providers.UserProvider.GetDetails(bodyJSON.Username)
if err != nil {
ctx.Error(fmt.Errorf("Error while retrieving details from user %s: %s", bodyJSON.Username, err.Error()), authenticationFailedMessage)
return
}
ctx.Logger.Debugf("Details for user %s => groups: %s, emails %s", bodyJSON.Username, userDetails.Groups, userDetails.Emails)
// And set those information in the new session.
userSession := ctx.GetSession()
userSession.Username = bodyJSON.Username
userSession.Groups = userDetails.Groups
userSession.Emails = userDetails.Emails
userSession.AuthenticationLevel = authentication.OneFactor
userSession.LastActivity = time.Now().Unix()
err = ctx.SaveSession(userSession)
if err != nil {
ctx.Error(fmt.Errorf("Unable to save session of user %s", bodyJSON.Username), authenticationFailedMessage)
return
}
if bodyJSON.TargetURL != "" {
targetURL, err := url.ParseRequestURI(bodyJSON.TargetURL)
if err != nil {
ctx.Error(fmt.Errorf("Unable to parse target URL %s: %s", bodyJSON.TargetURL, err), authenticationFailedMessage)
return
}
requiredLevel := ctx.Providers.Authorizer.GetRequiredLevel(authorization.Subject{
Username: userSession.Username,
Groups: userSession.Groups,
IP: ctx.RemoteIP(),
}, *targetURL)
ctx.Logger.Debugf("Required level for the URL %s is %d", targetURL.String(), requiredLevel)
safeRedirection := isRedirectionSafe(*targetURL, ctx.Configuration.Session.Domain)
if safeRedirection && requiredLevel <= authorization.OneFactor {
response := redirectResponse{bodyJSON.TargetURL}
ctx.SetJSONBody(response)
} else {
ctx.ReplyOK()
}
} else {
ctx.ReplyOK()
}
}