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

go-pkgz / auth / 7255079117

18 Dec 2023 11:27PM UTC coverage: 82.941%. Remained the same
7255079117

Pull #189

github

web-flow
Bump golang.org/x/crypto from 0.14.0 to 0.17.0 in /_example

Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #189: Bump golang.org/x/crypto from 0.14.0 to 0.17.0 in /_example

2572 of 3101 relevant lines covered (82.94%)

6.93 hits per line

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

77.78
/provider/dev_provider.go
1
package provider
2

3
import (
4
        "context"
5
        "fmt"
6
        "html/template"
7
        "net/http"
8
        "strings"
9
        "sync"
10
        "time"
11

12
        "golang.org/x/oauth2"
13

14
        "github.com/go-pkgz/auth/avatar"
15
        "github.com/go-pkgz/auth/logger"
16
        "github.com/go-pkgz/auth/token"
17
)
18

19
const (
20
        defDevAuthPort = 8084
21
        defDevAuthHost = "127.0.0.1"
22
)
23

24
// DevAuthServer is a fake oauth server for development
25
// it provides stand-alone server running on its own port and pretending to be the real oauth2. It also provides
26
// Dev Provider the same way as normal providers do, i.e. like github, google and others.
27
// can run in interactive and non-interactive mode. In interactive mode login attempts will show login form to select
28
// desired user name, this is the mode used for development. Non-interactive mode for tests only.
29
type DevAuthServer struct {
30
        logger.L
31
        Provider   Oauth2Handler
32
        Automatic  bool
33
        GetEmailFn func(string) string
34
        username   string // unsafe, but fine for dev
35
        httpServer *http.Server
36
        lock       sync.Mutex
37
}
38

39
// Run oauth2 dev server on port devAuthPort
40
func (d *DevAuthServer) Run(ctx context.Context) { // nolint (gocyclo)
2✔
41
        if d.Provider.Port == 0 {
2✔
42
                d.Provider.Port = defDevAuthPort
×
43
        }
×
44
        if d.Provider.Host == "" {
2✔
45
                d.Provider.Host = defDevAuthHost
×
46
        }
×
47

48
        d.username = "dev_user"
2✔
49
        d.Logf("[INFO] run local oauth2 dev server on %d, redirect url=%s", d.Provider.Port, d.Provider.conf.RedirectURL)
2✔
50
        d.lock.Lock()
2✔
51
        var err error
2✔
52

2✔
53
        userFormTmpl, err := template.New("page").Parse(devUserFormTmpl)
2✔
54
        if err != nil {
2✔
55
                d.Logf("[WARN] can't parse user form template, %s", err)
×
56
                return
×
57
        }
×
58

59
        d.httpServer = &http.Server{
2✔
60
                Addr:              fmt.Sprintf(":%d", d.Provider.Port),
2✔
61
                ReadHeaderTimeout: 5 * time.Second,
2✔
62
                Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
6✔
63
                        d.Logf("[DEBUG] dev oauth request %s %s %+v", r.Method, r.URL, r.Header)
4✔
64
                        switch {
4✔
65

66
                        case strings.HasPrefix(r.URL.Path, "/login/oauth/authorize"):
1✔
67

1✔
68
                                // first time it will be called without username and will ask for one
1✔
69
                                if !d.Automatic && (r.ParseForm() != nil || r.Form.Get("username") == "") {
1✔
70
                                        formData := struct{ Query template.URL }{Query: template.URL(r.URL.RawQuery)} //nolint:gosec // query is safe
×
71
                                        if err = userFormTmpl.Execute(w, formData); err != nil {
×
72
                                                d.Logf("[WARN] can't write, %s", err)
×
73
                                        }
×
74
                                        return
×
75
                                }
76

77
                                if !d.Automatic {
1✔
78
                                        d.username = r.Form.Get("username")
×
79
                                }
×
80

81
                                state := r.URL.Query().Get("state")
1✔
82
                                callbackURL := fmt.Sprintf("%s?code=g0ZGZmNjVmOWI&state=%s", d.Provider.conf.RedirectURL, state)
1✔
83
                                d.Logf("[DEBUG] callback url=%s", callbackURL)
1✔
84
                                w.Header().Add("Location", callbackURL)
1✔
85
                                w.WriteHeader(http.StatusFound)
1✔
86

87
                        case strings.HasPrefix(r.URL.Path, "/login/oauth/access_token"):
1✔
88
                                res := `{
1✔
89
                                        "access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
1✔
90
                                        "token_type":"bearer",
1✔
91
                                        "expires_in":3600,
1✔
92
                                        "refresh_token":"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
1✔
93
                                        "scope":"create",
1✔
94
                                        "state":"12345678"
1✔
95
                                        }`
1✔
96
                                w.Header().Set("Content-Type", "application/json; charset=utf-8")
1✔
97
                                if _, err = w.Write([]byte(res)); err != nil {
1✔
98
                                        w.WriteHeader(http.StatusInternalServerError)
×
99
                                        return
×
100
                                }
×
101

102
                        case strings.HasPrefix(r.URL.Path, "/user"):
1✔
103
                                ava := fmt.Sprintf("http://%s:%d/avatar?user=%s", d.Provider.Host, d.Provider.Port, d.username)
1✔
104
                                res := fmt.Sprintf(`{
1✔
105
                                        "id": "%s",
1✔
106
                                        "name":"%s",
1✔
107
                                        "picture":"%s"
1✔
108
                                        }`, d.username, d.username, ava)
1✔
109

1✔
110
                                if d.GetEmailFn != nil {
2✔
111
                                        email := d.GetEmailFn(d.username)
1✔
112
                                        res = fmt.Sprintf(`{
1✔
113
                                        "id": "%s",
1✔
114
                                        "name":"%s",
1✔
115
                                        "picture":"%s",
1✔
116
                                        "email": "%s"
1✔
117
                                        }`, d.username, d.username, ava, email)
1✔
118
                                }
1✔
119

120
                                w.Header().Set("Content-Type", "application/json; charset=utf-8")
1✔
121
                                if _, err = w.Write([]byte(res)); err != nil {
1✔
122
                                        w.WriteHeader(http.StatusInternalServerError)
×
123
                                        return
×
124
                                }
×
125

126
                        case strings.HasPrefix(r.URL.Path, "/avatar"):
1✔
127
                                user := r.URL.Query().Get("user")
1✔
128
                                b, e := avatar.GenerateAvatar(user)
1✔
129
                                if e != nil {
1✔
130
                                        w.WriteHeader(http.StatusNotFound)
×
131
                                        return
×
132
                                }
×
133
                                if _, err = w.Write(b); err != nil {
1✔
134
                                        w.WriteHeader(http.StatusInternalServerError)
×
135
                                        return
×
136
                                }
×
137

138
                        default:
×
139
                                w.WriteHeader(http.StatusBadRequest)
×
140
                        }
141
                }),
142
        }
143
        d.lock.Unlock()
2✔
144

2✔
145
        go func() {
4✔
146
                <-ctx.Done()
2✔
147
                d.Logf("[DEBUG] cancellation via context, %v", ctx.Err())
2✔
148
                d.Shutdown()
2✔
149
        }()
2✔
150

151
        err = d.httpServer.ListenAndServe()
2✔
152
        d.Logf("[WARN] dev oauth2 server terminated, %s", err)
2✔
153
}
154

155
// Shutdown oauth2 dev server
156
func (d *DevAuthServer) Shutdown() {
2✔
157
        d.Logf("[WARN] shutdown oauth2 dev server")
2✔
158
        ctx, cancel := context.WithTimeout(context.Background(), time.Second)
2✔
159
        defer cancel()
2✔
160
        d.lock.Lock()
2✔
161
        if d.httpServer != nil {
4✔
162
                if err := d.httpServer.Shutdown(ctx); err != nil {
2✔
163
                        d.Logf("[DEBUG] oauth2 dev shutdown error, %s", err)
×
164
                }
×
165
        }
166
        d.Logf("[DEBUG] shutdown dev oauth2 server completed")
2✔
167
        d.lock.Unlock()
2✔
168
}
169

170
// NewDev makes dev oauth2 provider for admin user
171
func NewDev(p Params) Oauth2Handler {
2✔
172
        if p.Port == 0 {
3✔
173
                p.Port = defDevAuthPort
1✔
174
        }
1✔
175
        if p.Host == "" {
4✔
176
                p.Host = defDevAuthHost
2✔
177
        }
2✔
178
        oh := initOauth2Handler(p, Oauth2Handler{
2✔
179
                name: "dev",
2✔
180
                endpoint: oauth2.Endpoint{
2✔
181
                        AuthURL:  fmt.Sprintf("http://%s:%d/login/oauth/authorize", p.Host, p.Port),
2✔
182
                        TokenURL: fmt.Sprintf("http://%s:%d/login/oauth/access_token", p.Host, p.Port),
2✔
183
                },
2✔
184
                scopes:  []string{"user:email"},
2✔
185
                infoURL: fmt.Sprintf("http://%s:%d/user", p.Host, p.Port),
2✔
186
                mapUser: func(data UserData, _ []byte) token.User {
3✔
187
                        userInfo := token.User{
1✔
188
                                ID:      data.Value("id"),
1✔
189
                                Name:    data.Value("name"),
1✔
190
                                Picture: data.Value("picture"),
1✔
191
                                Email:   data.Value("email"),
1✔
192
                        }
1✔
193
                        return userInfo
1✔
194
                },
1✔
195
        })
196

197
        oh.conf.RedirectURL = p.URL + "/auth/dev/callback"
2✔
198
        return oh
2✔
199
}
200

201
var devUserFormTmpl = `
202
<html>
203
        <head>
204
                <title>Dev OAuth</title>
205
                <style>
206
                        body {
207
                                text-align: center;
208
                        }
209

210
                        a {
211
                                color: hsl(200, 50%, 50%);
212
                                text-decoration-color: hsla(200, 50%, 50%, 0.5);
213
                        }
214

215
                        a:hover {
216
                                color: hsl(200, 50%, 70%);
217
                                text-decoration-color: hsla(200, 50%, 70%, 0.5);
218
                        }
219

220
                        form {
221
                                font-family: Helvetica, Arial, sans-serif;
222
                                margin: 100px auto;
223
                                display: inline-block;
224
                                padding: 1em;
225
                                box-shadow: 0 0 0.1rem rgba(0, 0, 0, 0.2), 0 0 0.4rem rgba(0, 0, 0, 0.1);
226
                        }
227

228
                        .form-header {
229
                                text-align: center;
230
                        }
231

232
                        .form-header h1 {
233
                                margin: 0;
234
                        }
235

236
                        .form-header h1 a:not(:hover) {
237
                                text-decoration: none;
238
                        }
239

240
                        .form-header p {
241
                                opacity: 0.6;
242
                                margin-top: 0;
243
                                margin-bottom: 2rem;
244
                        }
245

246
                        .username-label {
247
                                opacity: 0.6;
248
                                font-size: 0.8em;
249
                        }
250

251
                        .username-input {
252
                                font-size: inherit;
253
                                margin: 0;
254
                                width: 100%;
255
                                text-align: inherit;
256
                        }
257

258
                        .form-submit {
259
                                border: none;
260
                                background: hsl(200, 50%, 50%);
261
                                color: white;
262
                                font: inherit;
263
                                padding: 0.4em 0.8em 0.3em 0.8em;
264
                                border-radius: 0.2em;
265
                                width: 100%;
266
                        }
267

268
                        .form-submit:hover,
269
                        .form-submit:focus {
270
                                background-color: hsl(200, 50%, 70%);
271
                        }
272

273
                        .form-submit:active {
274
                                background-color: hsl(200, 80%, 70%);
275
                        }
276

277
                        .username-label,
278
                        .username-input,
279
                        .form-submit {
280
                                display: block;
281
                                margin-bottom: 0.4rem;
282
                        }
283

284
                        .notice {
285
                                margin: 0;
286
                                margin-top: 2rem;
287
                                font-size: 0.8em;
288
                                opacity: 0.6;
289
                        }
290
                </style>
291
        </head>
292
        <body>
293
                <form action="/login/oauth/authorize?{{.Query}}" method="post">
294
                        <header class="form-header">
295
                                <h1><a href="https://github.com/go-pkgz/auth">GO-PKGZ/AUTH</a></h1>
296
                                <p>Dev Provider</p>
297
                        </header>
298
                        <label>
299
                                <span class="username-label">Username</span>
300
                                <input
301
                                        class="username-input"
302
                                        type="text"
303
                                        name="username"
304
                                        value="dev_user"
305
                                        autofocus
306
                                />
307
                        </label>
308
                        <input type="submit" class="form-submit" value="Authorize" />
309
                        <p class="notice">Not for production use</p>
310
                </form>
311
        </body>
312
        <script>
313
                var input = document.querySelector(".username-input");
314
                input.focus();
315
                input.setSelectionRange(0, input.value.length)
316
        </script>
317
</html>
318
`
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