gitea

Зеркало из https://github.com/go-gitea/gitea
Форк
0
/
oauth2.go 
650 строк · 20.9 Кб
1
// Copyright 2019 The Gitea Authors. All rights reserved.
2
// SPDX-License-Identifier: MIT
3

4
package auth
5

6
import (
7
	"context"
8
	"crypto/sha256"
9
	"encoding/base32"
10
	"encoding/base64"
11
	"errors"
12
	"fmt"
13
	"net"
14
	"net/url"
15
	"strings"
16

17
	"code.gitea.io/gitea/models/db"
18
	"code.gitea.io/gitea/modules/container"
19
	"code.gitea.io/gitea/modules/setting"
20
	"code.gitea.io/gitea/modules/timeutil"
21
	"code.gitea.io/gitea/modules/util"
22

23
	uuid "github.com/google/uuid"
24
	"golang.org/x/crypto/bcrypt"
25
	"xorm.io/builder"
26
	"xorm.io/xorm"
27
)
28

29
// OAuth2Application represents an OAuth2 client (RFC 6749)
30
type OAuth2Application struct {
31
	ID           int64 `xorm:"pk autoincr"`
32
	UID          int64 `xorm:"INDEX"`
33
	Name         string
34
	ClientID     string `xorm:"unique"`
35
	ClientSecret string
36
	// OAuth defines both Confidential and Public client types
37
	// https://datatracker.ietf.org/doc/html/rfc6749#section-2.1
38
	// "Authorization servers MUST record the client type in the client registration details"
39
	// https://datatracker.ietf.org/doc/html/rfc8252#section-8.4
40
	ConfidentialClient         bool               `xorm:"NOT NULL DEFAULT TRUE"`
41
	SkipSecondaryAuthorization bool               `xorm:"NOT NULL DEFAULT FALSE"`
42
	RedirectURIs               []string           `xorm:"redirect_uris JSON TEXT"`
43
	CreatedUnix                timeutil.TimeStamp `xorm:"INDEX created"`
44
	UpdatedUnix                timeutil.TimeStamp `xorm:"INDEX updated"`
45
}
46

47
func init() {
48
	db.RegisterModel(new(OAuth2Application))
49
	db.RegisterModel(new(OAuth2AuthorizationCode))
50
	db.RegisterModel(new(OAuth2Grant))
51
}
52

53
type BuiltinOAuth2Application struct {
54
	ConfigName   string
55
	DisplayName  string
56
	RedirectURIs []string
57
}
58

59
func BuiltinApplications() map[string]*BuiltinOAuth2Application {
60
	m := make(map[string]*BuiltinOAuth2Application)
61
	m["a4792ccc-144e-407e-86c9-5e7d8d9c3269"] = &BuiltinOAuth2Application{
62
		ConfigName:   "git-credential-oauth",
63
		DisplayName:  "git-credential-oauth",
64
		RedirectURIs: []string{"http://127.0.0.1", "https://127.0.0.1"},
65
	}
66
	m["e90ee53c-94e2-48ac-9358-a874fb9e0662"] = &BuiltinOAuth2Application{
67
		ConfigName:   "git-credential-manager",
68
		DisplayName:  "Git Credential Manager",
69
		RedirectURIs: []string{"http://127.0.0.1", "https://127.0.0.1"},
70
	}
71
	m["d57cb8c4-630c-4168-8324-ec79935e18d4"] = &BuiltinOAuth2Application{
72
		ConfigName:   "tea",
73
		DisplayName:  "tea",
74
		RedirectURIs: []string{"http://127.0.0.1", "https://127.0.0.1"},
75
	}
76
	return m
77
}
78

79
func Init(ctx context.Context) error {
80
	builtinApps := BuiltinApplications()
81
	var builtinAllClientIDs []string
82
	for clientID := range builtinApps {
83
		builtinAllClientIDs = append(builtinAllClientIDs, clientID)
84
	}
85

86
	var registeredApps []*OAuth2Application
87
	if err := db.GetEngine(ctx).In("client_id", builtinAllClientIDs).Find(&registeredApps); err != nil {
88
		return err
89
	}
90

91
	clientIDsToAdd := container.Set[string]{}
92
	for _, configName := range setting.OAuth2.DefaultApplications {
93
		found := false
94
		for clientID, builtinApp := range builtinApps {
95
			if builtinApp.ConfigName == configName {
96
				clientIDsToAdd.Add(clientID) // add all user-configured apps to the "add" list
97
				found = true
98
			}
99
		}
100
		if !found {
101
			return fmt.Errorf("unknown oauth2 application: %q", configName)
102
		}
103
	}
104
	clientIDsToDelete := container.Set[string]{}
105
	for _, app := range registeredApps {
106
		if !clientIDsToAdd.Contains(app.ClientID) {
107
			clientIDsToDelete.Add(app.ClientID) // if a registered app is not in the "add" list, it should be deleted
108
		}
109
	}
110
	for _, app := range registeredApps {
111
		clientIDsToAdd.Remove(app.ClientID) // no need to re-add existing (registered) apps, so remove them from the set
112
	}
113

114
	for _, app := range registeredApps {
115
		if clientIDsToDelete.Contains(app.ClientID) {
116
			if err := deleteOAuth2Application(ctx, app.ID, 0); err != nil {
117
				return err
118
			}
119
		}
120
	}
121
	for clientID := range clientIDsToAdd {
122
		builtinApp := builtinApps[clientID]
123
		if err := db.Insert(ctx, &OAuth2Application{
124
			Name:         builtinApp.DisplayName,
125
			ClientID:     clientID,
126
			RedirectURIs: builtinApp.RedirectURIs,
127
		}); err != nil {
128
			return err
129
		}
130
	}
131

132
	return nil
133
}
134

135
// TableName sets the table name to `oauth2_application`
136
func (app *OAuth2Application) TableName() string {
137
	return "oauth2_application"
138
}
139

140
// ContainsRedirectURI checks if redirectURI is allowed for app
141
func (app *OAuth2Application) ContainsRedirectURI(redirectURI string) bool {
142
	// OAuth2 requires the redirect URI to be an exact match, no dynamic parts are allowed.
143
	// https://stackoverflow.com/questions/55524480/should-dynamic-query-parameters-be-present-in-the-redirection-uri-for-an-oauth2
144
	// https://www.rfc-editor.org/rfc/rfc6819#section-5.2.3.3
145
	// https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
146
	// https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics-12#section-3.1
147
	contains := func(s string) bool {
148
		s = strings.TrimSuffix(strings.ToLower(s), "/")
149
		for _, u := range app.RedirectURIs {
150
			if strings.TrimSuffix(strings.ToLower(u), "/") == s {
151
				return true
152
			}
153
		}
154
		return false
155
	}
156
	if !app.ConfidentialClient {
157
		uri, err := url.Parse(redirectURI)
158
		// ignore port for http loopback uris following https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
159
		if err == nil && uri.Scheme == "http" && uri.Port() != "" {
160
			ip := net.ParseIP(uri.Hostname())
161
			if ip != nil && ip.IsLoopback() {
162
				// strip port
163
				uri.Host = uri.Hostname()
164
				if contains(uri.String()) {
165
					return true
166
				}
167
			}
168
		}
169
	}
170
	return contains(redirectURI)
171
}
172

173
// Base32 characters, but lowercased.
174
const lowerBase32Chars = "abcdefghijklmnopqrstuvwxyz234567"
175

176
// base32 encoder that uses lowered characters without padding.
177
var base32Lower = base32.NewEncoding(lowerBase32Chars).WithPadding(base32.NoPadding)
178

179
// GenerateClientSecret will generate the client secret and returns the plaintext and saves the hash at the database
180
func (app *OAuth2Application) GenerateClientSecret(ctx context.Context) (string, error) {
181
	rBytes, err := util.CryptoRandomBytes(32)
182
	if err != nil {
183
		return "", err
184
	}
185
	// Add a prefix to the base32, this is in order to make it easier
186
	// for code scanners to grab sensitive tokens.
187
	clientSecret := "gto_" + base32Lower.EncodeToString(rBytes)
188

189
	hashedSecret, err := bcrypt.GenerateFromPassword([]byte(clientSecret), bcrypt.DefaultCost)
190
	if err != nil {
191
		return "", err
192
	}
193
	app.ClientSecret = string(hashedSecret)
194
	if _, err := db.GetEngine(ctx).ID(app.ID).Cols("client_secret").Update(app); err != nil {
195
		return "", err
196
	}
197
	return clientSecret, nil
198
}
199

200
// ValidateClientSecret validates the given secret by the hash saved in database
201
func (app *OAuth2Application) ValidateClientSecret(secret []byte) bool {
202
	return bcrypt.CompareHashAndPassword([]byte(app.ClientSecret), secret) == nil
203
}
204

205
// GetGrantByUserID returns a OAuth2Grant by its user and application ID
206
func (app *OAuth2Application) GetGrantByUserID(ctx context.Context, userID int64) (grant *OAuth2Grant, err error) {
207
	grant = new(OAuth2Grant)
208
	if has, err := db.GetEngine(ctx).Where("user_id = ? AND application_id = ?", userID, app.ID).Get(grant); err != nil {
209
		return nil, err
210
	} else if !has {
211
		return nil, nil
212
	}
213
	return grant, nil
214
}
215

216
// CreateGrant generates a grant for an user
217
func (app *OAuth2Application) CreateGrant(ctx context.Context, userID int64, scope string) (*OAuth2Grant, error) {
218
	grant := &OAuth2Grant{
219
		ApplicationID: app.ID,
220
		UserID:        userID,
221
		Scope:         scope,
222
	}
223
	err := db.Insert(ctx, grant)
224
	if err != nil {
225
		return nil, err
226
	}
227
	return grant, nil
228
}
229

230
// GetOAuth2ApplicationByClientID returns the oauth2 application with the given client_id. Returns an error if not found.
231
func GetOAuth2ApplicationByClientID(ctx context.Context, clientID string) (app *OAuth2Application, err error) {
232
	app = new(OAuth2Application)
233
	has, err := db.GetEngine(ctx).Where("client_id = ?", clientID).Get(app)
234
	if !has {
235
		return nil, ErrOAuthClientIDInvalid{ClientID: clientID}
236
	}
237
	return app, err
238
}
239

240
// GetOAuth2ApplicationByID returns the oauth2 application with the given id. Returns an error if not found.
241
func GetOAuth2ApplicationByID(ctx context.Context, id int64) (app *OAuth2Application, err error) {
242
	app = new(OAuth2Application)
243
	has, err := db.GetEngine(ctx).ID(id).Get(app)
244
	if err != nil {
245
		return nil, err
246
	}
247
	if !has {
248
		return nil, ErrOAuthApplicationNotFound{ID: id}
249
	}
250
	return app, nil
251
}
252

253
// CreateOAuth2ApplicationOptions holds options to create an oauth2 application
254
type CreateOAuth2ApplicationOptions struct {
255
	Name                       string
256
	UserID                     int64
257
	ConfidentialClient         bool
258
	SkipSecondaryAuthorization bool
259
	RedirectURIs               []string
260
}
261

262
// CreateOAuth2Application inserts a new oauth2 application
263
func CreateOAuth2Application(ctx context.Context, opts CreateOAuth2ApplicationOptions) (*OAuth2Application, error) {
264
	clientID := uuid.New().String()
265
	app := &OAuth2Application{
266
		UID:                        opts.UserID,
267
		Name:                       opts.Name,
268
		ClientID:                   clientID,
269
		RedirectURIs:               opts.RedirectURIs,
270
		ConfidentialClient:         opts.ConfidentialClient,
271
		SkipSecondaryAuthorization: opts.SkipSecondaryAuthorization,
272
	}
273
	if err := db.Insert(ctx, app); err != nil {
274
		return nil, err
275
	}
276
	return app, nil
277
}
278

279
// UpdateOAuth2ApplicationOptions holds options to update an oauth2 application
280
type UpdateOAuth2ApplicationOptions struct {
281
	ID                         int64
282
	Name                       string
283
	UserID                     int64
284
	ConfidentialClient         bool
285
	SkipSecondaryAuthorization bool
286
	RedirectURIs               []string
287
}
288

289
// UpdateOAuth2Application updates an oauth2 application
290
func UpdateOAuth2Application(ctx context.Context, opts UpdateOAuth2ApplicationOptions) (*OAuth2Application, error) {
291
	ctx, committer, err := db.TxContext(ctx)
292
	if err != nil {
293
		return nil, err
294
	}
295
	defer committer.Close()
296

297
	app, err := GetOAuth2ApplicationByID(ctx, opts.ID)
298
	if err != nil {
299
		return nil, err
300
	}
301
	if app.UID != opts.UserID {
302
		return nil, errors.New("UID mismatch")
303
	}
304
	builtinApps := BuiltinApplications()
305
	if _, builtin := builtinApps[app.ClientID]; builtin {
306
		return nil, fmt.Errorf("failed to edit OAuth2 application: application is locked: %s", app.ClientID)
307
	}
308

309
	app.Name = opts.Name
310
	app.RedirectURIs = opts.RedirectURIs
311
	app.ConfidentialClient = opts.ConfidentialClient
312
	app.SkipSecondaryAuthorization = opts.SkipSecondaryAuthorization
313

314
	if err = updateOAuth2Application(ctx, app); err != nil {
315
		return nil, err
316
	}
317
	app.ClientSecret = ""
318

319
	return app, committer.Commit()
320
}
321

322
func updateOAuth2Application(ctx context.Context, app *OAuth2Application) error {
323
	if _, err := db.GetEngine(ctx).ID(app.ID).UseBool("confidential_client", "skip_secondary_authorization").Update(app); err != nil {
324
		return err
325
	}
326
	return nil
327
}
328

329
func deleteOAuth2Application(ctx context.Context, id, userid int64) error {
330
	sess := db.GetEngine(ctx)
331
	// the userid could be 0 if the app is instance-wide
332
	if deleted, err := sess.Where(builder.Eq{"id": id, "uid": userid}).Delete(&OAuth2Application{}); err != nil {
333
		return err
334
	} else if deleted == 0 {
335
		return ErrOAuthApplicationNotFound{ID: id}
336
	}
337
	codes := make([]*OAuth2AuthorizationCode, 0)
338
	// delete correlating auth codes
339
	if err := sess.Join("INNER", "oauth2_grant",
340
		"oauth2_authorization_code.grant_id = oauth2_grant.id AND oauth2_grant.application_id = ?", id).Find(&codes); err != nil {
341
		return err
342
	}
343
	codeIDs := make([]int64, 0, len(codes))
344
	for _, grant := range codes {
345
		codeIDs = append(codeIDs, grant.ID)
346
	}
347

348
	if _, err := sess.In("id", codeIDs).Delete(new(OAuth2AuthorizationCode)); err != nil {
349
		return err
350
	}
351

352
	if _, err := sess.Where("application_id = ?", id).Delete(new(OAuth2Grant)); err != nil {
353
		return err
354
	}
355
	return nil
356
}
357

358
// DeleteOAuth2Application deletes the application with the given id and the grants and auth codes related to it. It checks if the userid was the creator of the app.
359
func DeleteOAuth2Application(ctx context.Context, id, userid int64) error {
360
	ctx, committer, err := db.TxContext(ctx)
361
	if err != nil {
362
		return err
363
	}
364
	defer committer.Close()
365
	app, err := GetOAuth2ApplicationByID(ctx, id)
366
	if err != nil {
367
		return err
368
	}
369
	builtinApps := BuiltinApplications()
370
	if _, builtin := builtinApps[app.ClientID]; builtin {
371
		return fmt.Errorf("failed to delete OAuth2 application: application is locked: %s", app.ClientID)
372
	}
373
	if err := deleteOAuth2Application(ctx, id, userid); err != nil {
374
		return err
375
	}
376
	return committer.Commit()
377
}
378

379
//////////////////////////////////////////////////////
380

381
// OAuth2AuthorizationCode is a code to obtain an access token in combination with the client secret once. It has a limited lifetime.
382
type OAuth2AuthorizationCode struct {
383
	ID                  int64        `xorm:"pk autoincr"`
384
	Grant               *OAuth2Grant `xorm:"-"`
385
	GrantID             int64
386
	Code                string `xorm:"INDEX unique"`
387
	CodeChallenge       string
388
	CodeChallengeMethod string
389
	RedirectURI         string
390
	ValidUntil          timeutil.TimeStamp `xorm:"index"`
391
}
392

393
// TableName sets the table name to `oauth2_authorization_code`
394
func (code *OAuth2AuthorizationCode) TableName() string {
395
	return "oauth2_authorization_code"
396
}
397

398
// GenerateRedirectURI generates a redirect URI for a successful authorization request. State will be used if not empty.
399
func (code *OAuth2AuthorizationCode) GenerateRedirectURI(state string) (*url.URL, error) {
400
	redirect, err := url.Parse(code.RedirectURI)
401
	if err != nil {
402
		return nil, err
403
	}
404
	q := redirect.Query()
405
	if state != "" {
406
		q.Set("state", state)
407
	}
408
	q.Set("code", code.Code)
409
	redirect.RawQuery = q.Encode()
410
	return redirect, err
411
}
412

413
// Invalidate deletes the auth code from the database to invalidate this code
414
func (code *OAuth2AuthorizationCode) Invalidate(ctx context.Context) error {
415
	_, err := db.GetEngine(ctx).ID(code.ID).NoAutoCondition().Delete(code)
416
	return err
417
}
418

419
// ValidateCodeChallenge validates the given verifier against the saved code challenge. This is part of the PKCE implementation.
420
func (code *OAuth2AuthorizationCode) ValidateCodeChallenge(verifier string) bool {
421
	switch code.CodeChallengeMethod {
422
	case "S256":
423
		// base64url(SHA256(verifier)) see https://tools.ietf.org/html/rfc7636#section-4.6
424
		h := sha256.Sum256([]byte(verifier))
425
		hashedVerifier := base64.RawURLEncoding.EncodeToString(h[:])
426
		return hashedVerifier == code.CodeChallenge
427
	case "plain":
428
		return verifier == code.CodeChallenge
429
	case "":
430
		return true
431
	default:
432
		// unsupported method -> return false
433
		return false
434
	}
435
}
436

437
// GetOAuth2AuthorizationByCode returns an authorization by its code
438
func GetOAuth2AuthorizationByCode(ctx context.Context, code string) (auth *OAuth2AuthorizationCode, err error) {
439
	auth = new(OAuth2AuthorizationCode)
440
	if has, err := db.GetEngine(ctx).Where("code = ?", code).Get(auth); err != nil {
441
		return nil, err
442
	} else if !has {
443
		return nil, nil
444
	}
445
	auth.Grant = new(OAuth2Grant)
446
	if has, err := db.GetEngine(ctx).ID(auth.GrantID).Get(auth.Grant); err != nil {
447
		return nil, err
448
	} else if !has {
449
		return nil, nil
450
	}
451
	return auth, nil
452
}
453

454
//////////////////////////////////////////////////////
455

456
// OAuth2Grant represents the permission of an user for a specific application to access resources
457
type OAuth2Grant struct {
458
	ID            int64              `xorm:"pk autoincr"`
459
	UserID        int64              `xorm:"INDEX unique(user_application)"`
460
	Application   *OAuth2Application `xorm:"-"`
461
	ApplicationID int64              `xorm:"INDEX unique(user_application)"`
462
	Counter       int64              `xorm:"NOT NULL DEFAULT 1"`
463
	Scope         string             `xorm:"TEXT"`
464
	Nonce         string             `xorm:"TEXT"`
465
	CreatedUnix   timeutil.TimeStamp `xorm:"created"`
466
	UpdatedUnix   timeutil.TimeStamp `xorm:"updated"`
467
}
468

469
// TableName sets the table name to `oauth2_grant`
470
func (grant *OAuth2Grant) TableName() string {
471
	return "oauth2_grant"
472
}
473

474
// GenerateNewAuthorizationCode generates a new authorization code for a grant and saves it to the database
475
func (grant *OAuth2Grant) GenerateNewAuthorizationCode(ctx context.Context, redirectURI, codeChallenge, codeChallengeMethod string) (code *OAuth2AuthorizationCode, err error) {
476
	rBytes, err := util.CryptoRandomBytes(32)
477
	if err != nil {
478
		return &OAuth2AuthorizationCode{}, err
479
	}
480
	// Add a prefix to the base32, this is in order to make it easier
481
	// for code scanners to grab sensitive tokens.
482
	codeSecret := "gta_" + base32Lower.EncodeToString(rBytes)
483

484
	code = &OAuth2AuthorizationCode{
485
		Grant:               grant,
486
		GrantID:             grant.ID,
487
		RedirectURI:         redirectURI,
488
		Code:                codeSecret,
489
		CodeChallenge:       codeChallenge,
490
		CodeChallengeMethod: codeChallengeMethod,
491
	}
492
	if err := db.Insert(ctx, code); err != nil {
493
		return nil, err
494
	}
495
	return code, nil
496
}
497

498
// IncreaseCounter increases the counter and updates the grant
499
func (grant *OAuth2Grant) IncreaseCounter(ctx context.Context) error {
500
	_, err := db.GetEngine(ctx).ID(grant.ID).Incr("counter").Update(new(OAuth2Grant))
501
	if err != nil {
502
		return err
503
	}
504
	updatedGrant, err := GetOAuth2GrantByID(ctx, grant.ID)
505
	if err != nil {
506
		return err
507
	}
508
	grant.Counter = updatedGrant.Counter
509
	return nil
510
}
511

512
// ScopeContains returns true if the grant scope contains the specified scope
513
func (grant *OAuth2Grant) ScopeContains(scope string) bool {
514
	for _, currentScope := range strings.Split(grant.Scope, " ") {
515
		if scope == currentScope {
516
			return true
517
		}
518
	}
519
	return false
520
}
521

522
// SetNonce updates the current nonce value of a grant
523
func (grant *OAuth2Grant) SetNonce(ctx context.Context, nonce string) error {
524
	grant.Nonce = nonce
525
	_, err := db.GetEngine(ctx).ID(grant.ID).Cols("nonce").Update(grant)
526
	if err != nil {
527
		return err
528
	}
529
	return nil
530
}
531

532
// GetOAuth2GrantByID returns the grant with the given ID
533
func GetOAuth2GrantByID(ctx context.Context, id int64) (grant *OAuth2Grant, err error) {
534
	grant = new(OAuth2Grant)
535
	if has, err := db.GetEngine(ctx).ID(id).Get(grant); err != nil {
536
		return nil, err
537
	} else if !has {
538
		return nil, nil
539
	}
540
	return grant, err
541
}
542

543
// GetOAuth2GrantsByUserID lists all grants of a certain user
544
func GetOAuth2GrantsByUserID(ctx context.Context, uid int64) ([]*OAuth2Grant, error) {
545
	type joinedOAuth2Grant struct {
546
		Grant       *OAuth2Grant       `xorm:"extends"`
547
		Application *OAuth2Application `xorm:"extends"`
548
	}
549
	var results *xorm.Rows
550
	var err error
551
	if results, err = db.GetEngine(ctx).
552
		Table("oauth2_grant").
553
		Where("user_id = ?", uid).
554
		Join("INNER", "oauth2_application", "application_id = oauth2_application.id").
555
		Rows(new(joinedOAuth2Grant)); err != nil {
556
		return nil, err
557
	}
558
	defer results.Close()
559
	grants := make([]*OAuth2Grant, 0)
560
	for results.Next() {
561
		joinedGrant := new(joinedOAuth2Grant)
562
		if err := results.Scan(joinedGrant); err != nil {
563
			return nil, err
564
		}
565
		joinedGrant.Grant.Application = joinedGrant.Application
566
		grants = append(grants, joinedGrant.Grant)
567
	}
568
	return grants, nil
569
}
570

571
// RevokeOAuth2Grant deletes the grant with grantID and userID
572
func RevokeOAuth2Grant(ctx context.Context, grantID, userID int64) error {
573
	_, err := db.GetEngine(ctx).Where(builder.Eq{"id": grantID, "user_id": userID}).Delete(&OAuth2Grant{})
574
	return err
575
}
576

577
// ErrOAuthClientIDInvalid will be thrown if client id cannot be found
578
type ErrOAuthClientIDInvalid struct {
579
	ClientID string
580
}
581

582
// IsErrOauthClientIDInvalid checks if an error is a ErrOAuthClientIDInvalid.
583
func IsErrOauthClientIDInvalid(err error) bool {
584
	_, ok := err.(ErrOAuthClientIDInvalid)
585
	return ok
586
}
587

588
// Error returns the error message
589
func (err ErrOAuthClientIDInvalid) Error() string {
590
	return fmt.Sprintf("Client ID invalid [Client ID: %s]", err.ClientID)
591
}
592

593
// Unwrap unwraps this as a ErrNotExist err
594
func (err ErrOAuthClientIDInvalid) Unwrap() error {
595
	return util.ErrNotExist
596
}
597

598
// ErrOAuthApplicationNotFound will be thrown if id cannot be found
599
type ErrOAuthApplicationNotFound struct {
600
	ID int64
601
}
602

603
// IsErrOAuthApplicationNotFound checks if an error is a ErrReviewNotExist.
604
func IsErrOAuthApplicationNotFound(err error) bool {
605
	_, ok := err.(ErrOAuthApplicationNotFound)
606
	return ok
607
}
608

609
// Error returns the error message
610
func (err ErrOAuthApplicationNotFound) Error() string {
611
	return fmt.Sprintf("OAuth application not found [ID: %d]", err.ID)
612
}
613

614
// Unwrap unwraps this as a ErrNotExist err
615
func (err ErrOAuthApplicationNotFound) Unwrap() error {
616
	return util.ErrNotExist
617
}
618

619
// GetActiveOAuth2SourceByName returns a OAuth2 AuthSource based on the given name
620
func GetActiveOAuth2SourceByName(ctx context.Context, name string) (*Source, error) {
621
	authSource := new(Source)
622
	has, err := db.GetEngine(ctx).Where("name = ? and type = ? and is_active = ?", name, OAuth2, true).Get(authSource)
623
	if err != nil {
624
		return nil, err
625
	}
626

627
	if !has {
628
		return nil, fmt.Errorf("oauth2 source not found, name: %q", name)
629
	}
630

631
	return authSource, nil
632
}
633

634
func DeleteOAuth2RelictsByUserID(ctx context.Context, userID int64) error {
635
	deleteCond := builder.Select("id").From("oauth2_grant").Where(builder.Eq{"oauth2_grant.user_id": userID})
636

637
	if _, err := db.GetEngine(ctx).In("grant_id", deleteCond).
638
		Delete(&OAuth2AuthorizationCode{}); err != nil {
639
		return err
640
	}
641

642
	if err := db.DeleteBeans(ctx,
643
		&OAuth2Application{UID: userID},
644
		&OAuth2Grant{UserID: userID},
645
	); err != nil {
646
		return fmt.Errorf("DeleteBeans: %w", err)
647
	}
648

649
	return nil
650
}
651

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.