This is an automated email from the ASF dual-hosted git repository.

abeizn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git


The following commit(s) were added to refs/heads/main by this push:
     new 2227ba5aa refactor: revert auth mechansim in favor of oauth2_proxy 
(#5396)
2227ba5aa is described below

commit 2227ba5aa6589f640dea2a5b977aa6693c6a23a2
Author: Klesh Wong <[email protected]>
AuthorDate: Wed Jun 7 16:34:00 2023 +0800

    refactor: revert auth mechansim in favor of oauth2_proxy (#5396)
---
 backend/server/api/api.go               |  11 --
 backend/server/api/login/login.go       | 107 -------------
 backend/server/services/auth/auth.go    | 110 -------------
 backend/server/services/auth/cognito.go | 276 --------------------------------
 backend/server/services/init.go         |   3 -
 env.example                             |   8 -
 6 files changed, 515 deletions(-)

diff --git a/backend/server/api/api.go b/backend/server/api/api.go
index f187206e8..24a017129 100644
--- a/backend/server/api/api.go
+++ b/backend/server/api/api.go
@@ -35,12 +35,10 @@ import (
        "github.com/apache/incubator-devlake/core/plugin"
        "github.com/apache/incubator-devlake/impls/logruslog"
        _ "github.com/apache/incubator-devlake/server/api/docs"
-       "github.com/apache/incubator-devlake/server/api/login"
        "github.com/apache/incubator-devlake/server/api/ping"
        "github.com/apache/incubator-devlake/server/api/shared"
        "github.com/apache/incubator-devlake/server/api/version"
        "github.com/apache/incubator-devlake/server/services"
-       "github.com/apache/incubator-devlake/server/services/auth"
 )
 
 const DB_MIGRATION_REQUIRED = `
@@ -70,15 +68,6 @@ func CreateApiService() {
        router.GET("/ping", ping.Get)
        router.GET("/version", version.Get)
 
-       if auth.Enabled() {
-               // Add login endpoint
-               router.POST("/login", login.Login)
-               router.POST("/login/newpassword", login.NewPassword)
-               router.POST("/login/refreshtoken", login.RefreshToken)
-               // Use AuthenticationMiddleware for protected routes
-               router.Use(auth.Middleware)
-       }
-
        // Endpoint to proceed database migration
        router.GET("/proceed-db-migration", func(ctx *gin.Context) {
                // Check if migration requires confirmation
diff --git a/backend/server/api/login/login.go 
b/backend/server/api/login/login.go
deleted file mode 100644
index 7ef7f6d45..000000000
--- a/backend/server/api/login/login.go
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package login
-
-import (
-       "net/http"
-
-       "github.com/apache/incubator-devlake/core/errors"
-       "github.com/apache/incubator-devlake/server/api/shared"
-       "github.com/apache/incubator-devlake/server/services/auth"
-
-       "github.com/gin-gonic/gin"
-)
-
-// @Summary post login
-// @Description post login
-// @Tags framework/login
-// @Accept application/json
-// @Param login body auth.LoginRequest true "json"
-// @Success 200  {object} auth.LoginResponse
-// @Failure 400  {object} shared.ApiBody "Bad Request"
-// @Failure 500  {object} shared.ApiBody "Internal Error"
-// @Router /login [post]
-func Login(ctx *gin.Context) {
-       loginReq := &auth.LoginRequest{}
-       err := ctx.ShouldBind(loginReq)
-       if err != nil {
-               shared.ApiOutputError(ctx, errors.BadInput.Wrap(err, 
shared.BadRequestBody))
-               return
-       }
-       res, err := auth.Provider.SignIn(loginReq)
-       if err != nil {
-               shared.ApiOutputError(ctx, errors.Default.Wrap(err, "error 
signing in"))
-               return
-       }
-       if res.AuthenticationResult != nil && 
res.AuthenticationResult.AccessToken != nil {
-               token, err := 
auth.Provider.CheckAuth(*res.AuthenticationResult.AccessToken)
-               if err != nil {
-                       shared.ApiOutputAbort(ctx, err)
-               }
-               ctx.Set("token", token)
-       }
-       shared.ApiOutputSuccess(ctx, res, http.StatusOK)
-}
-
-// @Summary post NewPassword
-// @Description post NewPassword
-// @Tags framework/NewPassword
-// @Accept application/json
-// @Param newpassword body auth.NewPasswordRequest true "json"
-// @Success 200  {object} auth.LoginResponse
-// @Failure 400  {object} shared.ApiBody "Bad Request"
-// @Failure 500  {object} shared.ApiBody "Internal Error"
-// @Router /password [post]
-func NewPassword(ctx *gin.Context) {
-       newPasswordReq := &auth.NewPasswordRequest{}
-       err := ctx.ShouldBind(newPasswordReq)
-       if err != nil {
-               shared.ApiOutputError(ctx, errors.BadInput.Wrap(err, 
shared.BadRequestBody))
-               return
-       }
-       res, err := auth.Provider.NewPassword(newPasswordReq)
-       if err != nil {
-               shared.ApiOutputError(ctx, errors.BadInput.Wrap(err, "failed to 
set new password"))
-               return
-       }
-       shared.ApiOutputSuccess(ctx, res, http.StatusOK)
-}
-
-// @Summary post RefreshToken
-// @Description post RefreshToken
-// @Tags framework/RefreshToken
-// @Accept application/json
-// @Param refreshtoken body auth.RefreshTokenRequest true "json"
-// @Success 200  {object} auth.LoginResponse
-// @Failure 400  {object} shared.ApiBody "Bad Request"
-// @Failure 500  {object} shared.ApiBody "Internal Error"
-// @Router /password [post]
-func RefreshToken(ctx *gin.Context) {
-       req := &auth.RefreshTokenRequest{}
-       err := ctx.ShouldBind(req)
-       if err != nil {
-               shared.ApiOutputError(ctx, errors.BadInput.Wrap(err, 
shared.BadRequestBody))
-               return
-       }
-       res, err := auth.Provider.RefreshToken(req)
-       if err != nil {
-               shared.ApiOutputError(ctx, errors.BadInput.Wrap(err, "failed to 
refresh token"))
-               return
-       }
-       shared.ApiOutputSuccess(ctx, res, http.StatusOK)
-}
diff --git a/backend/server/services/auth/auth.go 
b/backend/server/services/auth/auth.go
deleted file mode 100644
index fe839e2d3..000000000
--- a/backend/server/services/auth/auth.go
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package auth
-
-import (
-       "strings"
-
-       "github.com/apache/incubator-devlake/core/context"
-       "github.com/apache/incubator-devlake/core/errors"
-       "github.com/apache/incubator-devlake/server/api/shared"
-       "github.com/dgrijalva/jwt-go"
-       "github.com/gin-gonic/gin"
-)
-
-// data structures
-
-type LoginRequest struct {
-       Username string `json:"username"`
-       Password string `json:"password"`
-}
-
-type LoginResponse struct {
-       AuthenticationResult *AuthenticationResult `json:"authenticationResult"`
-       ChallengeName        *string               `json:"challengeName"`
-       ChallengeParameters  map[string]*string    `json:"challengeParameters"`
-       Session              *string               `json:"session"`
-}
-
-type AuthenticationResult struct {
-       AccessToken  *string `json:"accessToken" type:"string" sensitive:"true"`
-       ExpiresIn    *int64  `json:"expiresIn" type:"integer"`
-       IdToken      *string `json:"idToken" type:"string" sensitive:"true"`
-       RefreshToken *string `json:"refreshToken" type:"string" 
sensitive:"true"`
-       TokenType    *string `json:"tokenType" type:"string"`
-}
-
-type NewPasswordRequest struct {
-       Username    string `json:"username"`
-       NewPassword string `json:"newPassword"`
-       Session     string `json:"session"`
-}
-
-type RefreshTokenRequest struct {
-       RefreshToken string `json:"refreshToken"`
-}
-
-// auth provider interface
-type AuthProvider interface {
-       SignIn(*LoginRequest) (*LoginResponse, errors.Error)
-       NewPassword(*NewPasswordRequest) (*LoginResponse, errors.Error)
-       RefreshToken(*RefreshTokenRequest) (*LoginResponse, errors.Error)
-       // ChangePassword(ctx *gin.Context, oldPassword, newPassword string) 
errors.Error
-       CheckAuth(token string) (*jwt.Token, errors.Error)
-}
-
-var Provider AuthProvider
-
-// initialize auth provider
-func InitProvider(basicRes context.BasicRes) {
-       v := basicRes.GetConfigReader()
-       awsCognitoEnabled := v.GetBool("AWS_ENABLE_COGNITO")
-       if awsCognitoEnabled {
-               Provider = NewCognitoProvider(basicRes)
-       }
-}
-
-func Middleware(ctx *gin.Context) {
-       if Provider == nil {
-               return
-       }
-       // Get the Auth header
-       authHeader := ctx.GetHeader("Authorization")
-       if authHeader == "" {
-               shared.ApiOutputAbort(ctx, 
errors.Unauthorized.New("Authorization header is missing"))
-               return
-       }
-
-       // Split the header into "Bearer" and the actual token
-       bearerToken := strings.Split(authHeader, " ")
-       if len(bearerToken) != 2 {
-               shared.ApiOutputAbort(ctx, errors.Unauthorized.New("Invalid 
Authorization header"))
-               return
-       }
-       token, err := Provider.CheckAuth(bearerToken[1])
-       if err != nil {
-               shared.ApiOutputAbort(ctx, err)
-               return
-       }
-
-       ctx.Set("token", token)
-}
-
-func Enabled() bool {
-       return Provider != nil
-}
diff --git a/backend/server/services/auth/cognito.go 
b/backend/server/services/auth/cognito.go
deleted file mode 100644
index 37c13f6ae..000000000
--- a/backend/server/services/auth/cognito.go
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package auth
-
-import (
-       "crypto/rsa"
-       "encoding/base64"
-       "encoding/json"
-       "fmt"
-       "io"
-       "math/big"
-       "net/http"
-       "strings"
-
-       "github.com/apache/incubator-devlake/core/config"
-       "github.com/apache/incubator-devlake/core/context"
-       "github.com/apache/incubator-devlake/core/errors"
-       "github.com/apache/incubator-devlake/core/log"
-       "github.com/aws/aws-sdk-go/aws"
-       "github.com/aws/aws-sdk-go/aws/session"
-       "github.com/aws/aws-sdk-go/service/cognitoidentityprovider"
-       "github.com/dgrijalva/jwt-go"
-)
-
-type AwsCognitoProvider struct {
-       jwks         Jwks
-       logger       log.Logger
-       client       *cognitoidentityprovider.CognitoIdentityProvider
-       clientId     *string
-       expectClaims jwt.MapClaims
-}
-
-func NewCognitoProvider(basicRes context.BasicRes) *AwsCognitoProvider {
-       // Get configuration
-       v := config.GetConfig()
-       // TODO: verify the configuration
-       // Create an AWS session
-       sess := session.Must(session.NewSession(&aws.Config{
-               Region: aws.String(v.GetString("AWS_AUTH_REGION")),
-       }))
-       // Create a Cognito Identity Provider client
-       client := cognitoidentityprovider.New(sess)
-       cgt := &AwsCognitoProvider{
-               client:   client,
-               clientId: 
aws.String(v.GetString("AWS_AUTH_USER_POOL_WEB_CLIENT_ID")),
-               logger:   basicRes.GetLogger().Nested("cognito"),
-       }
-       // Fetch the JWKS from the Cognito User Pool
-       jwksURL := fmt.Sprintf(
-               "https://cognito-idp.%s.amazonaws.com/%s/.well-known/jwks.json";,
-               v.GetString("AWS_AUTH_REGION"),
-               v.GetString("AWS_AUTH_USER_POOL_ID"),
-       )
-       err := cgt.fetchJWKS(jwksURL)
-       if err != nil {
-               panic(err)
-       }
-       // Optional expect claims
-       expect_claims := 
strings.TrimSpace(v.GetString("AWS_AUTH_EXPECT_CLAIMS"))
-       if expect_claims != "" {
-               e := json.Unmarshal([]byte(expect_claims), &cgt.expectClaims)
-               if e != nil {
-                       panic(e)
-               }
-       }
-       return cgt
-}
-
-func (cgt *AwsCognitoProvider) fetchJWKS(jwksURL string) errors.Error {
-       // Get the JWKS from the URL
-       resp, err := http.Get(jwksURL)
-       if err != nil {
-               return errors.Default.Wrap(err, "Failed to fetch JWKS")
-       }
-       defer resp.Body.Close()
-
-       body, err := io.ReadAll(resp.Body)
-       if err != nil {
-               return errors.Default.Wrap(err, "Failed to read JWKS")
-       }
-       // Unmarshal the response into a Jwks struct
-       err = json.Unmarshal(body, &cgt.jwks)
-       if err != nil {
-               return errors.Default.Wrap(err, "Failed to unmarshall JWKS")
-       }
-       return nil
-}
-
-func (cgt *AwsCognitoProvider) SignIn(loginReq *LoginRequest) (*LoginResponse, 
errors.Error) {
-       // Create the input for InitiateAuth
-       input := &cognitoidentityprovider.InitiateAuthInput{
-               AuthFlow: aws.String("USER_PASSWORD_AUTH"),
-               ClientId: cgt.clientId,
-               AuthParameters: map[string]*string{
-                       "USERNAME": aws.String(loginReq.Username),
-                       "PASSWORD": aws.String(loginReq.Password),
-               },
-       }
-
-       // Call Cognito to get auth tokens
-       return cgt.initiateAuth(input)
-}
-
-func (cgt *AwsCognitoProvider) initiateAuth(input 
*cognitoidentityprovider.InitiateAuthInput) (*LoginResponse, errors.Error) {
-       response, err := cgt.client.InitiateAuth(input)
-       if err != nil {
-               return nil, errors.BadInput.New(err.Error())
-       }
-       loginRes := &LoginResponse{
-               ChallengeName:       response.ChallengeName,
-               ChallengeParameters: response.ChallengeParameters,
-               Session:             response.Session,
-       }
-       if response.AuthenticationResult != nil {
-               loginRes.AuthenticationResult = &AuthenticationResult{
-                       AccessToken:  response.AuthenticationResult.AccessToken,
-                       ExpiresIn:    response.AuthenticationResult.ExpiresIn,
-                       IdToken:      response.AuthenticationResult.IdToken,
-                       RefreshToken: 
response.AuthenticationResult.RefreshToken,
-                       TokenType:    response.AuthenticationResult.TokenType,
-               }
-       }
-       return loginRes, nil
-}
-
-func (cgt *AwsCognitoProvider) CheckAuth(tokenString string) (*jwt.Token, 
errors.Error) {
-       // Parse the JWT token
-       token, err := jwt.Parse(tokenString, func(token *jwt.Token) 
(interface{}, error) {
-               // Check the signing method
-               if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
-                       return nil, 
errors.Unauthorized.New(fmt.Sprintf("Unexpected signing method: %v", 
token.Header["alg"]))
-               }
-
-               // Get the key ID from the header
-               kid := token.Header["kid"].(string)
-
-               // Look for the key that matches the kid
-               for _, key := range cgt.jwks.Keys {
-                       if key.Kid == kid {
-                               // Construct the RSA public key
-                               n := pemHeader(key.N)
-                               e := pemHeader(key.E)
-                               parsedKey := &rsa.PublicKey{
-                                       N: new(big.Int).SetBytes(n),
-                                       E: 
int(new(big.Int).SetBytes(e).Int64()),
-                               }
-                               return parsedKey, nil
-                       }
-               }
-
-               return nil, fmt.Errorf("Public key not found")
-       })
-
-       if err != nil {
-               if ve, ok := err.(*jwt.ValidationError); ok {
-                       if ve.Errors == jwt.ValidationErrorExpired {
-                               return nil, errors.Forbidden.New("Token 
expired")
-                       }
-               }
-       }
-
-       // Check if the token is valid
-       if err != nil || !token.Valid {
-               cgt.logger.Error(err, "Invalid token")
-               return nil, errors.Unauthorized.New("Invalid token")
-       }
-
-       // verify claims
-       if len(cgt.expectClaims) > 0 {
-               if actualClaims, ok := token.Claims.(jwt.MapClaims); ok {
-                       for key, expected := range cgt.expectClaims {
-                               if expected != actualClaims[key] {
-                                       return nil, 
errors.Unauthorized.New("Invalid token: expected claims do not match")
-                               }
-                       }
-               } else {
-                       return nil, errors.Unauthorized.New("Invalid token: 
expected claims do not match")
-               }
-       }
-
-       return token, nil
-}
-
-func pemHeader(encodedKey string) []byte {
-       // Decode the base64 encoded key
-       key, err := base64.RawURLEncoding.DecodeString(encodedKey)
-       if err != nil {
-               return nil
-       }
-       return key
-}
-
-// Jwks represents the JSON web key set
-type Jwks struct {
-       Keys []struct {
-               Kid string `json:"kid"`
-               N   string `json:"n"`
-               E   string `json:"e"`
-       } `json:"keys"`
-}
-
-func (cgt *AwsCognitoProvider) NewPassword(newPasswordReq *NewPasswordRequest) 
(*LoginResponse, errors.Error) {
-       input := &cognitoidentityprovider.RespondToAuthChallengeInput{
-               ChallengeName: aws.String("NEW_PASSWORD_REQUIRED"),
-               ChallengeResponses: map[string]*string{
-                       "USERNAME":     aws.String(newPasswordReq.Username),
-                       "NEW_PASSWORD": aws.String(newPasswordReq.NewPassword),
-               },
-               Session:  aws.String(newPasswordReq.Session),
-               ClientId: cgt.clientId,
-       }
-       response, err := cgt.client.RespondToAuthChallenge(input)
-       if err != nil {
-               return nil, errors.BadInput.Wrap(err, "Error setting up new 
password: "+err.Error())
-       }
-       // yes , it is identical to the login response, and yet they are 2 
different structs
-       loginRes := &LoginResponse{
-               ChallengeName:       response.ChallengeName,
-               ChallengeParameters: response.ChallengeParameters,
-               Session:             response.Session,
-       }
-       if response.AuthenticationResult != nil {
-               loginRes.AuthenticationResult = &AuthenticationResult{
-                       AccessToken:  response.AuthenticationResult.AccessToken,
-                       ExpiresIn:    response.AuthenticationResult.ExpiresIn,
-                       IdToken:      response.AuthenticationResult.IdToken,
-                       RefreshToken: 
response.AuthenticationResult.RefreshToken,
-                       TokenType:    response.AuthenticationResult.TokenType,
-               }
-       }
-       return loginRes, nil
-}
-
-func (cgt *AwsCognitoProvider) RefreshToken(req *RefreshTokenRequest) 
(*LoginResponse, errors.Error) {
-       // Create the input for InitiateAuth
-       input := &cognitoidentityprovider.InitiateAuthInput{
-               AuthFlow: 
aws.String(cognitoidentityprovider.AuthFlowTypeRefreshTokenAuth),
-               ClientId: cgt.clientId,
-               AuthParameters: map[string]*string{
-                       "REFRESH_TOKEN": aws.String(req.RefreshToken),
-               },
-       }
-       return cgt.initiateAuth(input)
-}
-
-// func (cgt *AwsCognitorProvider) ChangePassword(ctx *gin.Context, 
oldPassword, newPassword string) errors.Error {
-//     token := ctx.GetString(("token"))
-//     if token == "" {
-//             return errors.Unauthorized.New("Token is missing")
-//     }
-//     input := &cognitoidentityprovider.ChangePasswordInput{
-//             AccessToken:      &token,
-//             PreviousPassword: &oldPassword,
-//             ProposedPassword: &newPassword,
-//     }
-//     _, err := cgt.client.ChangePassword(input)
-//     if err != nil {
-//             return errors.BadInput.Wrap(err, "Error changing password")
-//     }
-//     return nil
-// }
diff --git a/backend/server/services/init.go b/backend/server/services/init.go
index e4f9c065b..f3f4e4e72 100644
--- a/backend/server/services/init.go
+++ b/backend/server/services/init.go
@@ -32,7 +32,6 @@ import (
        "github.com/apache/incubator-devlake/helpers/pluginhelper/services"
        "github.com/apache/incubator-devlake/impls/dalgorm"
        "github.com/apache/incubator-devlake/impls/logruslog"
-       "github.com/apache/incubator-devlake/server/services/auth"
        "github.com/go-playground/validator/v10"
        "github.com/robfig/cron/v3"
 )
@@ -84,8 +83,6 @@ func GetMigrator() plugin.Migrator {
 func Init() {
        InitResources()
 
-       auth.InitProvider(basicRes)
-
        // lock the database to avoid multiple devlake instances from sharing 
the same one
        lockDb()
 
diff --git a/env.example b/env.example
index 917126c1a..718be78cc 100644
--- a/env.example
+++ b/env.example
@@ -46,11 +46,3 @@ ENCRYPTION_SECRET=
 # Set if skip verify and connect with out trusted certificate when use https
 ##########################
 IN_SECURE_SKIP_VERIFY=
-
-
-# aws cognito
-AWS_ENABLE_COGNITO=
-AWS_AUTH_REGION=
-AWS_AUTH_USER_POOL_ID=
-AWS_AUTH_USER_POOL_WEB_CLIENT_ID=
-AWS_AUTH_COOKIE_STORAGE_DOMAIN=

Reply via email to