-
Notifications
You must be signed in to change notification settings - Fork 908
/
driver_common.go
144 lines (113 loc) · 4.04 KB
/
driver_common.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
//go:build linux && cgo && !agent
package auth
import (
"fmt"
"net/http"
"net/url"
"github.com/canonical/lxd/lxd/request"
"github.com/canonical/lxd/shared"
"github.com/canonical/lxd/shared/api"
"github.com/canonical/lxd/shared/logger"
)
type commonAuthorizer struct {
driverName string
logger logger.Logger
}
func (c *commonAuthorizer) init(driverName string, l logger.Logger) error {
if l == nil {
return fmt.Errorf("Cannot initialise authorizer: nil logger provided")
}
l = l.AddContext(logger.Ctx{"driver": driverName})
c.driverName = driverName
c.logger = l
return nil
}
type requestDetails struct {
trusted bool
userName string
protocol string
forwardedUsername string
forwardedProtocol string
isAllProjectsRequest bool
projectName string
isPKI bool
idpGroups []string
forwardedIDPGroups []string
}
func (r *requestDetails) isInternalOrUnix() bool {
if r.protocol == "unix" {
return true
}
if r.protocol == "cluster" && (r.forwardedProtocol == "unix" || r.forwardedProtocol == "cluster" || r.forwardedProtocol == "") {
return true
}
return false
}
func (r *requestDetails) username() string {
if r.protocol == "cluster" && r.forwardedUsername != "" {
return r.forwardedUsername
}
return r.userName
}
func (r *requestDetails) authenticationProtocol() string {
if r.protocol == "cluster" {
return r.forwardedProtocol
}
return r.protocol
}
func (r *requestDetails) identityProviderGroups() []string {
if r.protocol == "cluster" {
return r.forwardedIDPGroups
}
return r.idpGroups
}
func (c *commonAuthorizer) requestDetails(r *http.Request) (*requestDetails, error) {
if r == nil {
return nil, api.StatusErrorf(http.StatusInternalServerError, "Cannot inspect nil request")
} else if r.URL == nil {
return nil, api.StatusErrorf(http.StatusInternalServerError, "Request URL is not set")
}
var err error
d := &requestDetails{}
d.trusted, err = request.GetCtxValue[bool](r.Context(), request.CtxTrusted)
if err != nil {
return nil, api.StatusErrorf(http.StatusInternalServerError, "Failed getting authentication status: %w", err)
}
// If request is not trusted, no other values should be extracted.
if !d.trusted {
return d, nil
}
// Request protocol cannot be empty.
d.protocol, err = request.GetCtxValue[string](r.Context(), request.CtxProtocol)
if err != nil {
return nil, api.StatusErrorf(http.StatusInternalServerError, "Failed getting protocol: %w", err)
}
// Forwarded protocol can be empty.
d.forwardedProtocol, _ = request.GetCtxValue[string](r.Context(), request.CtxForwardedProtocol)
// If we're in a CA environment, it's possible for a certificate to be trusted despite not being present in the trust store.
// We rely on the validation of the certificate (and its potential revocation) having been done in CheckTrustState.
d.isPKI = d.authenticationProtocol() == api.AuthenticationMethodTLS && shared.PathExists(shared.VarPath("server.ca"))
// Username cannot be empty.
d.userName, err = request.GetCtxValue[string](r.Context(), request.CtxUsername)
if err != nil {
return nil, api.StatusErrorf(http.StatusInternalServerError, "Failed getting username: %w", err)
}
// Forwarded username can be empty.
d.forwardedUsername, _ = request.GetCtxValue[string](r.Context(), request.CtxForwardedUsername)
// Check for identity provider groups.
d.idpGroups, _ = request.GetCtxValue[[]string](r.Context(), request.CtxIdentityProviderGroups)
d.forwardedIDPGroups, _ = request.GetCtxValue[[]string](r.Context(), request.CtxForwardedIdentityProviderGroups)
// Check if the request is for all projects.
values, err := url.ParseQuery(r.URL.RawQuery)
if err != nil {
return nil, api.StatusErrorf(http.StatusBadRequest, "Failed to parse request query parameters: %w", err)
}
// Get project details.
d.isAllProjectsRequest = shared.IsTrue(values.Get("all-projects"))
d.projectName = request.ProjectParam(r)
return d, nil
}
// Driver returns the driver name.
func (c *commonAuthorizer) Driver() string {
return c.driverName
}