mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add oauth2 token exchange (#12196)
Co-authored-by: Steven Masley <stevenmasley@gmail.com>
This commit is contained in:
@@ -801,6 +801,25 @@ func (q *querier) DeleteOAuth2ProviderAppByID(ctx context.Context, id uuid.UUID)
|
||||
return q.db.DeleteOAuth2ProviderAppByID(ctx, id)
|
||||
}
|
||||
|
||||
func (q *querier) DeleteOAuth2ProviderAppCodeByID(ctx context.Context, id uuid.UUID) error {
|
||||
code, err := q.db.GetOAuth2ProviderAppCodeByID(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := q.authorizeContext(ctx, rbac.ActionDelete, code); err != nil {
|
||||
return err
|
||||
}
|
||||
return q.db.DeleteOAuth2ProviderAppCodeByID(ctx, id)
|
||||
}
|
||||
|
||||
func (q *querier) DeleteOAuth2ProviderAppCodesByAppAndUserID(ctx context.Context, arg database.DeleteOAuth2ProviderAppCodesByAppAndUserIDParams) error {
|
||||
if err := q.authorizeContext(ctx, rbac.ActionDelete,
|
||||
rbac.ResourceOAuth2ProviderAppCodeToken.WithOwner(arg.UserID.String())); err != nil {
|
||||
return err
|
||||
}
|
||||
return q.db.DeleteOAuth2ProviderAppCodesByAppAndUserID(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) DeleteOAuth2ProviderAppSecretByID(ctx context.Context, id uuid.UUID) error {
|
||||
if err := q.authorizeContext(ctx, rbac.ActionDelete, rbac.ResourceOAuth2ProviderAppSecret); err != nil {
|
||||
return err
|
||||
@@ -808,6 +827,14 @@ func (q *querier) DeleteOAuth2ProviderAppSecretByID(ctx context.Context, id uuid
|
||||
return q.db.DeleteOAuth2ProviderAppSecretByID(ctx, id)
|
||||
}
|
||||
|
||||
func (q *querier) DeleteOAuth2ProviderAppTokensByAppAndUserID(ctx context.Context, arg database.DeleteOAuth2ProviderAppTokensByAppAndUserIDParams) error {
|
||||
if err := q.authorizeContext(ctx, rbac.ActionDelete,
|
||||
rbac.ResourceOAuth2ProviderAppCodeToken.WithOwner(arg.UserID.String())); err != nil {
|
||||
return err
|
||||
}
|
||||
return q.db.DeleteOAuth2ProviderAppTokensByAppAndUserID(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) DeleteOldProvisionerDaemons(ctx context.Context) error {
|
||||
if err := q.authorizeContext(ctx, rbac.ActionDelete, rbac.ResourceSystem); err != nil {
|
||||
return err
|
||||
@@ -1175,6 +1202,14 @@ func (q *querier) GetOAuth2ProviderAppByID(ctx context.Context, id uuid.UUID) (d
|
||||
return q.db.GetOAuth2ProviderAppByID(ctx, id)
|
||||
}
|
||||
|
||||
func (q *querier) GetOAuth2ProviderAppCodeByID(ctx context.Context, id uuid.UUID) (database.OAuth2ProviderAppCode, error) {
|
||||
return fetch(q.log, q.auth, q.db.GetOAuth2ProviderAppCodeByID)(ctx, id)
|
||||
}
|
||||
|
||||
func (q *querier) GetOAuth2ProviderAppCodeByPrefix(ctx context.Context, secretPrefix []byte) (database.OAuth2ProviderAppCode, error) {
|
||||
return fetch(q.log, q.auth, q.db.GetOAuth2ProviderAppCodeByPrefix)(ctx, secretPrefix)
|
||||
}
|
||||
|
||||
func (q *querier) GetOAuth2ProviderAppSecretByID(ctx context.Context, id uuid.UUID) (database.OAuth2ProviderAppSecret, error) {
|
||||
if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceOAuth2ProviderAppSecret); err != nil {
|
||||
return database.OAuth2ProviderAppSecret{}, err
|
||||
@@ -1182,6 +1217,10 @@ func (q *querier) GetOAuth2ProviderAppSecretByID(ctx context.Context, id uuid.UU
|
||||
return q.db.GetOAuth2ProviderAppSecretByID(ctx, id)
|
||||
}
|
||||
|
||||
func (q *querier) GetOAuth2ProviderAppSecretByPrefix(ctx context.Context, secretPrefix []byte) (database.OAuth2ProviderAppSecret, error) {
|
||||
return fetch(q.log, q.auth, q.db.GetOAuth2ProviderAppSecretByPrefix)(ctx, secretPrefix)
|
||||
}
|
||||
|
||||
func (q *querier) GetOAuth2ProviderAppSecretsByAppID(ctx context.Context, appID uuid.UUID) ([]database.OAuth2ProviderAppSecret, error) {
|
||||
if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceOAuth2ProviderAppSecret); err != nil {
|
||||
return []database.OAuth2ProviderAppSecret{}, err
|
||||
@@ -1189,6 +1228,22 @@ func (q *querier) GetOAuth2ProviderAppSecretsByAppID(ctx context.Context, appID
|
||||
return q.db.GetOAuth2ProviderAppSecretsByAppID(ctx, appID)
|
||||
}
|
||||
|
||||
func (q *querier) GetOAuth2ProviderAppTokenByPrefix(ctx context.Context, hashPrefix []byte) (database.OAuth2ProviderAppToken, error) {
|
||||
token, err := q.db.GetOAuth2ProviderAppTokenByPrefix(ctx, hashPrefix)
|
||||
if err != nil {
|
||||
return database.OAuth2ProviderAppToken{}, err
|
||||
}
|
||||
// The user ID is on the API key so that has to be fetched.
|
||||
key, err := q.db.GetAPIKeyByID(ctx, token.APIKeyID)
|
||||
if err != nil {
|
||||
return database.OAuth2ProviderAppToken{}, err
|
||||
}
|
||||
if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceOAuth2ProviderAppCodeToken.WithOwner(key.UserID.String())); err != nil {
|
||||
return database.OAuth2ProviderAppToken{}, err
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (q *querier) GetOAuth2ProviderApps(ctx context.Context) ([]database.OAuth2ProviderApp, error) {
|
||||
if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceOAuth2ProviderApp); err != nil {
|
||||
return []database.OAuth2ProviderApp{}, err
|
||||
@@ -1196,6 +1251,15 @@ func (q *querier) GetOAuth2ProviderApps(ctx context.Context) ([]database.OAuth2P
|
||||
return q.db.GetOAuth2ProviderApps(ctx)
|
||||
}
|
||||
|
||||
func (q *querier) GetOAuth2ProviderAppsByUserID(ctx context.Context, userID uuid.UUID) ([]database.GetOAuth2ProviderAppsByUserIDRow, error) {
|
||||
// This authz check is to make sure the caller can read all their own tokens.
|
||||
if err := q.authorizeContext(ctx, rbac.ActionRead,
|
||||
rbac.ResourceOAuth2ProviderAppCodeToken.WithOwner(userID.String())); err != nil {
|
||||
return []database.GetOAuth2ProviderAppsByUserIDRow{}, err
|
||||
}
|
||||
return q.db.GetOAuth2ProviderAppsByUserID(ctx, userID)
|
||||
}
|
||||
|
||||
func (q *querier) GetOAuthSigningKey(ctx context.Context) (string, error) {
|
||||
if err := q.authorizeContext(ctx, rbac.ActionUpdate, rbac.ResourceSystem); err != nil {
|
||||
return "", err
|
||||
@@ -2242,6 +2306,14 @@ func (q *querier) InsertOAuth2ProviderApp(ctx context.Context, arg database.Inse
|
||||
return q.db.InsertOAuth2ProviderApp(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) InsertOAuth2ProviderAppCode(ctx context.Context, arg database.InsertOAuth2ProviderAppCodeParams) (database.OAuth2ProviderAppCode, error) {
|
||||
if err := q.authorizeContext(ctx, rbac.ActionCreate,
|
||||
rbac.ResourceOAuth2ProviderAppCodeToken.WithOwner(arg.UserID.String())); err != nil {
|
||||
return database.OAuth2ProviderAppCode{}, err
|
||||
}
|
||||
return q.db.InsertOAuth2ProviderAppCode(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) InsertOAuth2ProviderAppSecret(ctx context.Context, arg database.InsertOAuth2ProviderAppSecretParams) (database.OAuth2ProviderAppSecret, error) {
|
||||
if err := q.authorizeContext(ctx, rbac.ActionCreate, rbac.ResourceOAuth2ProviderAppSecret); err != nil {
|
||||
return database.OAuth2ProviderAppSecret{}, err
|
||||
@@ -2249,6 +2321,17 @@ func (q *querier) InsertOAuth2ProviderAppSecret(ctx context.Context, arg databas
|
||||
return q.db.InsertOAuth2ProviderAppSecret(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) InsertOAuth2ProviderAppToken(ctx context.Context, arg database.InsertOAuth2ProviderAppTokenParams) (database.OAuth2ProviderAppToken, error) {
|
||||
key, err := q.db.GetAPIKeyByID(ctx, arg.APIKeyID)
|
||||
if err != nil {
|
||||
return database.OAuth2ProviderAppToken{}, err
|
||||
}
|
||||
if err := q.authorizeContext(ctx, rbac.ActionCreate, rbac.ResourceOAuth2ProviderAppCodeToken.WithOwner(key.UserID.String())); err != nil {
|
||||
return database.OAuth2ProviderAppToken{}, err
|
||||
}
|
||||
return q.db.InsertOAuth2ProviderAppToken(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) InsertOrganization(ctx context.Context, arg database.InsertOrganizationParams) (database.Organization, error) {
|
||||
return insert(q.log, q.auth, rbac.ResourceOrganization, q.db.InsertOrganization)(ctx, arg)
|
||||
}
|
||||
|
||||
@@ -2316,6 +2316,34 @@ func (s *MethodTestSuite) TestOAuth2ProviderApps() {
|
||||
app := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{})
|
||||
check.Args(app.ID).Asserts(rbac.ResourceOAuth2ProviderApp, rbac.ActionRead).Returns(app)
|
||||
}))
|
||||
s.Run("GetOAuth2ProviderAppsByUserID", s.Subtest(func(db database.Store, check *expects) {
|
||||
user := dbgen.User(s.T(), db, database.User{})
|
||||
key, _ := dbgen.APIKey(s.T(), db, database.APIKey{
|
||||
UserID: user.ID,
|
||||
})
|
||||
app := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{})
|
||||
_ = dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{})
|
||||
secret := dbgen.OAuth2ProviderAppSecret(s.T(), db, database.OAuth2ProviderAppSecret{
|
||||
AppID: app.ID,
|
||||
})
|
||||
for i := 0; i < 5; i++ {
|
||||
_ = dbgen.OAuth2ProviderAppToken(s.T(), db, database.OAuth2ProviderAppToken{
|
||||
AppSecretID: secret.ID,
|
||||
APIKeyID: key.ID,
|
||||
})
|
||||
}
|
||||
check.Args(user.ID).Asserts(rbac.ResourceOAuth2ProviderAppCodeToken.WithOwner(user.ID.String()), rbac.ActionRead).Returns([]database.GetOAuth2ProviderAppsByUserIDRow{
|
||||
{
|
||||
OAuth2ProviderApp: database.OAuth2ProviderApp{
|
||||
ID: app.ID,
|
||||
CallbackURL: app.CallbackURL,
|
||||
Icon: app.Icon,
|
||||
Name: app.Name,
|
||||
},
|
||||
TokenCount: 5,
|
||||
},
|
||||
})
|
||||
}))
|
||||
s.Run("InsertOAuth2ProviderApp", s.Subtest(func(db database.Store, check *expects) {
|
||||
check.Args(database.InsertOAuth2ProviderAppParams{}).Asserts(rbac.ResourceOAuth2ProviderApp, rbac.ActionCreate)
|
||||
}))
|
||||
@@ -2361,6 +2389,13 @@ func (s *MethodTestSuite) TestOAuth2ProviderAppSecrets() {
|
||||
})
|
||||
check.Args(secret.ID).Asserts(rbac.ResourceOAuth2ProviderAppSecret, rbac.ActionRead).Returns(secret)
|
||||
}))
|
||||
s.Run("GetOAuth2ProviderAppSecretByPrefix", s.Subtest(func(db database.Store, check *expects) {
|
||||
app := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{})
|
||||
secret := dbgen.OAuth2ProviderAppSecret(s.T(), db, database.OAuth2ProviderAppSecret{
|
||||
AppID: app.ID,
|
||||
})
|
||||
check.Args(secret.SecretPrefix).Asserts(rbac.ResourceOAuth2ProviderAppSecret, rbac.ActionRead).Returns(secret)
|
||||
}))
|
||||
s.Run("InsertOAuth2ProviderAppSecret", s.Subtest(func(db database.Store, check *expects) {
|
||||
app := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{})
|
||||
check.Args(database.InsertOAuth2ProviderAppSecretParams{
|
||||
@@ -2386,3 +2421,107 @@ func (s *MethodTestSuite) TestOAuth2ProviderAppSecrets() {
|
||||
check.Args(secret.ID).Asserts(rbac.ResourceOAuth2ProviderAppSecret, rbac.ActionDelete)
|
||||
}))
|
||||
}
|
||||
|
||||
func (s *MethodTestSuite) TestOAuth2ProviderAppCodes() {
|
||||
s.Run("GetOAuth2ProviderAppCodeByID", s.Subtest(func(db database.Store, check *expects) {
|
||||
user := dbgen.User(s.T(), db, database.User{})
|
||||
app := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{})
|
||||
code := dbgen.OAuth2ProviderAppCode(s.T(), db, database.OAuth2ProviderAppCode{
|
||||
AppID: app.ID,
|
||||
UserID: user.ID,
|
||||
})
|
||||
check.Args(code.ID).Asserts(code, rbac.ActionRead).Returns(code)
|
||||
}))
|
||||
s.Run("GetOAuth2ProviderAppCodeByPrefix", s.Subtest(func(db database.Store, check *expects) {
|
||||
user := dbgen.User(s.T(), db, database.User{})
|
||||
app := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{})
|
||||
code := dbgen.OAuth2ProviderAppCode(s.T(), db, database.OAuth2ProviderAppCode{
|
||||
AppID: app.ID,
|
||||
UserID: user.ID,
|
||||
})
|
||||
check.Args(code.SecretPrefix).Asserts(code, rbac.ActionRead).Returns(code)
|
||||
}))
|
||||
s.Run("InsertOAuth2ProviderAppCode", s.Subtest(func(db database.Store, check *expects) {
|
||||
user := dbgen.User(s.T(), db, database.User{})
|
||||
app := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{})
|
||||
check.Args(database.InsertOAuth2ProviderAppCodeParams{
|
||||
AppID: app.ID,
|
||||
UserID: user.ID,
|
||||
}).Asserts(rbac.ResourceOAuth2ProviderAppCodeToken.WithOwner(user.ID.String()), rbac.ActionCreate)
|
||||
}))
|
||||
s.Run("DeleteOAuth2ProviderAppCodeByID", s.Subtest(func(db database.Store, check *expects) {
|
||||
user := dbgen.User(s.T(), db, database.User{})
|
||||
app := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{})
|
||||
code := dbgen.OAuth2ProviderAppCode(s.T(), db, database.OAuth2ProviderAppCode{
|
||||
AppID: app.ID,
|
||||
UserID: user.ID,
|
||||
})
|
||||
check.Args(code.ID).Asserts(code, rbac.ActionDelete)
|
||||
}))
|
||||
s.Run("DeleteOAuth2ProviderAppCodesByAppAndUserID", s.Subtest(func(db database.Store, check *expects) {
|
||||
user := dbgen.User(s.T(), db, database.User{})
|
||||
app := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{})
|
||||
for i := 0; i < 5; i++ {
|
||||
_ = dbgen.OAuth2ProviderAppCode(s.T(), db, database.OAuth2ProviderAppCode{
|
||||
AppID: app.ID,
|
||||
UserID: user.ID,
|
||||
})
|
||||
}
|
||||
check.Args(database.DeleteOAuth2ProviderAppCodesByAppAndUserIDParams{
|
||||
AppID: app.ID,
|
||||
UserID: user.ID,
|
||||
}).Asserts(rbac.ResourceOAuth2ProviderAppCodeToken.WithOwner(user.ID.String()), rbac.ActionDelete)
|
||||
}))
|
||||
}
|
||||
|
||||
func (s *MethodTestSuite) TestOAuth2ProviderAppTokens() {
|
||||
s.Run("InsertOAuth2ProviderAppToken", s.Subtest(func(db database.Store, check *expects) {
|
||||
user := dbgen.User(s.T(), db, database.User{})
|
||||
key, _ := dbgen.APIKey(s.T(), db, database.APIKey{
|
||||
UserID: user.ID,
|
||||
})
|
||||
app := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{})
|
||||
secret := dbgen.OAuth2ProviderAppSecret(s.T(), db, database.OAuth2ProviderAppSecret{
|
||||
AppID: app.ID,
|
||||
})
|
||||
check.Args(database.InsertOAuth2ProviderAppTokenParams{
|
||||
AppSecretID: secret.ID,
|
||||
APIKeyID: key.ID,
|
||||
}).Asserts(rbac.ResourceOAuth2ProviderAppCodeToken.WithOwner(user.ID.String()), rbac.ActionCreate)
|
||||
}))
|
||||
s.Run("GetOAuth2ProviderAppTokenByPrefix", s.Subtest(func(db database.Store, check *expects) {
|
||||
user := dbgen.User(s.T(), db, database.User{})
|
||||
key, _ := dbgen.APIKey(s.T(), db, database.APIKey{
|
||||
UserID: user.ID,
|
||||
})
|
||||
app := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{})
|
||||
secret := dbgen.OAuth2ProviderAppSecret(s.T(), db, database.OAuth2ProviderAppSecret{
|
||||
AppID: app.ID,
|
||||
})
|
||||
token := dbgen.OAuth2ProviderAppToken(s.T(), db, database.OAuth2ProviderAppToken{
|
||||
AppSecretID: secret.ID,
|
||||
APIKeyID: key.ID,
|
||||
})
|
||||
check.Args(token.HashPrefix).Asserts(rbac.ResourceOAuth2ProviderAppCodeToken.WithOwner(user.ID.String()), rbac.ActionRead)
|
||||
}))
|
||||
s.Run("DeleteOAuth2ProviderAppTokensByAppAndUserID", s.Subtest(func(db database.Store, check *expects) {
|
||||
user := dbgen.User(s.T(), db, database.User{})
|
||||
key, _ := dbgen.APIKey(s.T(), db, database.APIKey{
|
||||
UserID: user.ID,
|
||||
})
|
||||
app := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{})
|
||||
secret := dbgen.OAuth2ProviderAppSecret(s.T(), db, database.OAuth2ProviderAppSecret{
|
||||
AppID: app.ID,
|
||||
})
|
||||
for i := 0; i < 5; i++ {
|
||||
_ = dbgen.OAuth2ProviderAppToken(s.T(), db, database.OAuth2ProviderAppToken{
|
||||
AppSecretID: secret.ID,
|
||||
APIKeyID: key.ID,
|
||||
})
|
||||
}
|
||||
check.Args(database.DeleteOAuth2ProviderAppTokensByAppAndUserIDParams{
|
||||
AppID: app.ID,
|
||||
UserID: user.ID,
|
||||
}).Asserts(rbac.ResourceOAuth2ProviderAppCodeToken.WithOwner(user.ID.String()), rbac.ActionDelete)
|
||||
}))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user