/
handler_register_duo_device.go
146 lines (111 loc) · 4.55 KB
/
handler_register_duo_device.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
package handlers
import (
"fmt"
"net/url"
"strings"
"github.com/authelia/authelia/v4/internal/duo"
"github.com/authelia/authelia/v4/internal/middlewares"
"github.com/authelia/authelia/v4/internal/model"
"github.com/authelia/authelia/v4/internal/session"
"github.com/authelia/authelia/v4/internal/utils"
)
// DuoDevicesGET handler for retrieving available devices and capabilities from duo api.
func DuoDevicesGET(duoAPI duo.API) middlewares.RequestHandler {
return func(ctx *middlewares.AutheliaCtx) {
var (
userSession session.UserSession
err error
)
if userSession, err = ctx.GetSession(); err != nil {
ctx.Error(fmt.Errorf("failed to get session data: %w", err), messageMFAValidationFailed)
return
}
values := url.Values{}
values.Set("username", userSession.Username)
ctx.Logger.Debugf("Starting Duo PreAuth for %s", userSession.Username)
result, message, devices, enrollURL, err := DuoPreAuth(ctx, &userSession, duoAPI)
if err != nil {
ctx.Error(fmt.Errorf("duo PreAuth API errored: %w", err), messageMFAValidationFailed)
return
}
if result == auth {
if devices == nil {
ctx.Logger.Debugf("No applicable device/method available for Duo user %s", userSession.Username)
if err := ctx.SetJSONBody(DuoDevicesResponse{Result: enroll}); err != nil {
ctx.Error(fmt.Errorf("unable to set JSON body in response"), messageMFAValidationFailed)
}
return
}
if err := ctx.SetJSONBody(DuoDevicesResponse{Result: auth, Devices: devices}); err != nil {
ctx.Error(fmt.Errorf("unable to set JSON body in response"), messageMFAValidationFailed)
}
return
}
if result == allow {
ctx.Logger.Debugf("Device selection not possible for user %s, because Duo authentication was bypassed - Defaults to Auto Push", userSession.Username)
if err := ctx.SetJSONBody(DuoDevicesResponse{Result: allow}); err != nil {
ctx.Error(fmt.Errorf("unable to set JSON body in response"), messageMFAValidationFailed)
}
return
}
if result == enroll {
ctx.Logger.Debugf("Duo user: %s not enrolled", userSession.Username)
if err := ctx.SetJSONBody(DuoDevicesResponse{Result: enroll, EnrollURL: enrollURL}); err != nil {
ctx.Error(fmt.Errorf("unable to set JSON body in response"), messageMFAValidationFailed)
}
return
}
if result == deny {
ctx.Logger.Debugf("Duo User not allowed to authenticate: %s", userSession.Username)
if err := ctx.SetJSONBody(DuoDevicesResponse{Result: deny}); err != nil {
ctx.Error(fmt.Errorf("unable to set JSON body in response"), messageMFAValidationFailed)
}
return
}
ctx.Error(fmt.Errorf("duo PreAuth API errored for %s: %s - %s", userSession.Username, result, message), messageMFAValidationFailed)
}
}
// DuoDevicePOST update the user preferences regarding Duo device and method.
func DuoDevicePOST(ctx *middlewares.AutheliaCtx) {
bodyJSON := DuoDeviceBody{}
var (
userSession session.UserSession
err error
)
if err = ctx.ParseBody(&bodyJSON); err != nil {
ctx.Error(err, messageMFAValidationFailed)
return
}
if !utils.IsStringInSlice(bodyJSON.Method, duo.PossibleMethods) {
ctx.Error(fmt.Errorf("unknown method '%s', it should be one of %s", bodyJSON.Method, strings.Join(duo.PossibleMethods, ", ")), messageMFAValidationFailed)
return
}
if userSession, err = ctx.GetSession(); err != nil {
ctx.Error(err, messageMFAValidationFailed)
return
}
ctx.Logger.Debugf("Save new preferred Duo device and method of user %s to %s using %s", userSession.Username, bodyJSON.Device, bodyJSON.Method)
err = ctx.Providers.StorageProvider.SavePreferredDuoDevice(ctx, model.DuoDevice{Username: userSession.Username, Device: bodyJSON.Device, Method: bodyJSON.Method})
if err != nil {
ctx.Error(fmt.Errorf("unable to save new preferred Duo device and method: %w", err), messageMFAValidationFailed)
return
}
ctx.ReplyOK()
}
// DuoDeviceDELETE deletes the useres preferred Duo device and method.
func DuoDeviceDELETE(ctx *middlewares.AutheliaCtx) {
var (
userSession session.UserSession
err error
)
if userSession, err = ctx.GetSession(); err != nil {
ctx.Error(fmt.Errorf("unable to get session to delete preferred Duo device and method: %w", err), messageMFAValidationFailed)
return
}
ctx.Logger.Debugf("Deleting preferred Duo device and method of user %s", userSession.Username)
if err = ctx.Providers.StorageProvider.DeletePreferredDuoDevice(ctx, userSession.Username); err != nil {
ctx.Error(fmt.Errorf("unable to delete preferred Duo device and method: %w", err), messageMFAValidationFailed)
return
}
ctx.ReplyOK()
}