• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender-server / 1900805255

01 Jul 2025 05:31PM UTC coverage: 66.222% (+0.5%) from 65.694%
1900805255

Pull #774

gitlab-ci

web-flow
chore: bump pillow from 11.2.1 to 11.3.0 in /backend/tests

Bumps [pillow](https://github.com/python-pillow/Pillow) from 11.2.1 to 11.3.0.
- [Release notes](https://github.com/python-pillow/Pillow/releases)
- [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst)
- [Commits](https://github.com/python-pillow/Pillow/compare/11.2.1...11.3.0)

---
updated-dependencies:
- dependency-name: pillow
  dependency-version: 11.3.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #774: chore: bump pillow from 11.2.1 to 11.3.0 in /backend/tests

29486 of 44526 relevant lines covered (66.22%)

1.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.78
/backend/pkg/identity/middleware.go
1
// Copyright 2023 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
package identity
16

17
import (
18
        "net/http"
19
        "regexp"
20

21
        "github.com/ant0ine/go-json-rest/rest"
22
        "github.com/gin-gonic/gin"
23

24
        "github.com/mendersoftware/mender-server/pkg/log"
25
        urest "github.com/mendersoftware/mender-server/pkg/rest.utils"
26
)
27

28
type MiddlewareOptions struct {
29
        // PathRegex sets the regex for the path for which this middleware
30
        // applies. Defaults to "^/api/management/v[0-9.]{1,6}/.+".
31
        PathRegex *string
32

33
        // UpdateLogger adds the decoded identity to the log context.
34
        UpdateLogger *bool
35
}
36

37
func NewMiddlewareOptions() *MiddlewareOptions {
7✔
38
        return new(MiddlewareOptions)
7✔
39
}
7✔
40

41
func (opts *MiddlewareOptions) SetPathRegex(regex string) *MiddlewareOptions {
2✔
42
        opts.PathRegex = &regex
2✔
43
        return opts
2✔
44
}
2✔
45

46
func (opts *MiddlewareOptions) SetUpdateLogger(updateLogger bool) *MiddlewareOptions {
7✔
47
        opts.UpdateLogger = &updateLogger
7✔
48
        return opts
7✔
49
}
7✔
50

51
func middlewareWithLogger(c *gin.Context) {
7✔
52
        var (
7✔
53
                err    error
7✔
54
                jwt    string
7✔
55
                idty   Identity
7✔
56
                logCtx = log.Ctx{}
7✔
57
                key    = "sub"
7✔
58
                ctx    = c.Request.Context()
7✔
59
                l      = log.FromContext(ctx)
7✔
60
        )
7✔
61
        jwt, err = ExtractJWTFromHeader(c.Request)
7✔
62
        if err != nil {
10✔
63
                goto exitUnauthorized
3✔
64
        }
65
        idty, err = ExtractIdentity(jwt)
7✔
66
        if err != nil {
8✔
67
                goto exitUnauthorized
1✔
68
        }
69
        ctx = WithContext(ctx, &idty)
7✔
70
        if idty.IsDevice {
12✔
71
                key = "device_id"
5✔
72
        } else if idty.IsUser {
18✔
73
                key = "user_id"
6✔
74
        }
6✔
75
        logCtx[key] = idty.Subject
7✔
76
        if idty.Tenant != "" {
11✔
77
                logCtx["tenant_id"] = idty.Tenant
4✔
78
        }
4✔
79
        if idty.Plan != "" {
10✔
80
                logCtx["plan"] = idty.Plan
3✔
81
        }
3✔
82
        ctx = log.WithContext(ctx, l.F(logCtx))
7✔
83

7✔
84
        c.Request = c.Request.WithContext(ctx)
7✔
85
        return
7✔
86
exitUnauthorized:
7✔
87
        c.Header("WWW-Authenticate", `Bearer realm="ManagementJWT"`)
3✔
88
        urest.RenderError(c, http.StatusUnauthorized, err)
3✔
89
        c.Abort()
3✔
90
}
91

92
func middlewareBase(c *gin.Context) {
×
93
        var (
×
94
                err  error
×
95
                jwt  string
×
96
                idty Identity
×
97
                ctx  = c.Request.Context()
×
98
        )
×
99
        jwt, err = ExtractJWTFromHeader(c.Request)
×
100
        if err != nil {
×
101
                goto exitUnauthorized
×
102
        }
103
        idty, err = ExtractIdentity(jwt)
×
104
        if err != nil {
×
105
                goto exitUnauthorized
×
106
        }
107
        ctx = WithContext(ctx, &idty)
×
108
        c.Request = c.Request.WithContext(ctx)
×
109
        return
×
110
exitUnauthorized:
×
111
        c.Header("WWW-Authenticate", `Bearer realm="ManagementJWT"`)
×
112
        urest.RenderError(c, http.StatusUnauthorized, err)
×
113
        c.Abort()
×
114
}
115

116
func Middleware(opts ...*MiddlewareOptions) gin.HandlerFunc {
7✔
117

7✔
118
        var middleware gin.HandlerFunc
7✔
119

7✔
120
        // Initialize default options
7✔
121
        opt := NewMiddlewareOptions().
7✔
122
                SetUpdateLogger(true)
7✔
123
        for _, o := range opts {
9✔
124
                if o == nil {
2✔
125
                        continue
×
126
                }
127
                if o.PathRegex != nil {
4✔
128
                        opt.PathRegex = o.PathRegex
2✔
129
                }
2✔
130
                if o.UpdateLogger != nil {
2✔
131
                        opt.UpdateLogger = o.UpdateLogger
×
132
                }
×
133
        }
134

135
        if *opt.UpdateLogger {
14✔
136
                middleware = middlewareWithLogger
7✔
137
        } else {
7✔
138
                middleware = middlewareBase
×
139
        }
×
140

141
        if opt.PathRegex != nil {
9✔
142
                pathRegex := regexp.MustCompile(*opt.PathRegex)
2✔
143
                return func(c *gin.Context) {
4✔
144
                        if !pathRegex.MatchString(c.FullPath()) {
4✔
145
                                return
2✔
146
                        }
2✔
147
                        middleware(c)
2✔
148
                }
149
        }
150
        return middleware
6✔
151
}
152

153
// IdentityMiddleware adds the identity extracted from JWT token to the request's context.
154
// IdentityMiddleware does not perform any form of token signature verification.
155
// If it is not possible to extract identity from header error log will be generated.
156
// IdentityMiddleware will not stop control propagating through the chain in any case.
157
// It is recommended to use IdentityMiddleware with RequestLogMiddleware and
158
// RequestLogMiddleware should be placed before IdentityMiddleware.
159
// Otherwise, log generated by IdentityMiddleware will not contain "request_id" field.
160
type IdentityMiddleware struct {
161
        // If set to true, the middleware will update context logger setting
162
        // 'user_id' or 'device_id' to the value of subject field, if the token
163
        // is not a user or a device token, the middelware will add a 'sub'
164
        // field to the logger
165
        UpdateLogger bool
166
}
167

168
// MiddlewareFunc makes IdentityMiddleware implement the Middleware interface.
169
func (mw *IdentityMiddleware) MiddlewareFunc(h rest.HandlerFunc) rest.HandlerFunc {
2✔
170
        return func(w rest.ResponseWriter, r *rest.Request) {
4✔
171
                jwt, err := ExtractJWTFromHeader(r.Request)
2✔
172
                if err != nil {
4✔
173
                        h(w, r)
2✔
174
                        return
2✔
175
                }
2✔
176

177
                ctx := r.Context()
2✔
178
                l := log.FromContext(ctx)
2✔
179

2✔
180
                identity, err := ExtractIdentity(jwt)
2✔
181
                if err != nil {
3✔
182
                        l.Warnf("Failed to parse extracted JWT: %s",
1✔
183
                                err.Error(),
1✔
184
                        )
1✔
185
                } else {
3✔
186
                        if mw.UpdateLogger {
4✔
187
                                logCtx := log.Ctx{}
2✔
188

2✔
189
                                key := "sub"
2✔
190
                                if identity.IsDevice {
2✔
191
                                        key = "device_id"
×
192
                                } else if identity.IsUser {
4✔
193
                                        key = "user_id"
2✔
194
                                }
2✔
195

196
                                logCtx[key] = identity.Subject
2✔
197

2✔
198
                                if identity.Tenant != "" {
2✔
199
                                        logCtx["tenant_id"] = identity.Tenant
×
200
                                }
×
201

202
                                if identity.Plan != "" {
2✔
203
                                        logCtx["plan"] = identity.Plan
×
204
                                }
×
205

206
                                l = l.F(logCtx)
2✔
207
                                ctx = log.WithContext(ctx, l)
2✔
208
                        }
209
                        ctx = WithContext(ctx, &identity)
2✔
210
                        r.Request = r.WithContext(ctx)
2✔
211
                }
212

213
                h(w, r)
2✔
214
        }
215
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc