|
|
@@ -2,8 +2,11 @@ package middleware
|
|
|
|
|
|
import (
|
|
|
"bytes"
|
|
|
+ "context"
|
|
|
"encoding/json"
|
|
|
"errors"
|
|
|
+ "github.com/google/go-github/github"
|
|
|
+ "golang.org/x/oauth2"
|
|
|
"io/ioutil"
|
|
|
"net/http"
|
|
|
"net/url"
|
|
|
@@ -19,10 +22,11 @@ import (
|
|
|
|
|
|
// Auth implements the authorization functions
|
|
|
type Auth struct {
|
|
|
- store sessions.Store
|
|
|
- cookieName string
|
|
|
- tokenConf *token.TokenGeneratorConf
|
|
|
- repo *repository.Repository
|
|
|
+ store sessions.Store
|
|
|
+ cookieName string
|
|
|
+ tokenConf *token.TokenGeneratorConf
|
|
|
+ repo *repository.Repository
|
|
|
+ GithubProjectConf *oauth2.Config
|
|
|
}
|
|
|
|
|
|
// NewAuth returns a new Auth instance
|
|
|
@@ -31,8 +35,9 @@ func NewAuth(
|
|
|
cookieName string,
|
|
|
tokenConf *token.TokenGeneratorConf,
|
|
|
repo *repository.Repository,
|
|
|
+ GithubProjectConf *oauth2.Config,
|
|
|
) *Auth {
|
|
|
- return &Auth{store, cookieName, tokenConf, repo}
|
|
|
+ return &Auth{store, cookieName, tokenConf, repo, GithubProjectConf}
|
|
|
}
|
|
|
|
|
|
// BasicAuthenticate just checks that a user is logged in
|
|
|
@@ -394,10 +399,11 @@ func (auth *Auth) DoesUserHaveRegistryAccess(
|
|
|
})
|
|
|
}
|
|
|
|
|
|
-// DoesUserHaveGitRepoAccess looks for a project_id parameter and a
|
|
|
-// git_repo_id parameter, and verifies that the git repo belongs
|
|
|
-// to the project
|
|
|
-func (auth *Auth) DoesUserHaveGitRepoAccess(
|
|
|
+// DoesUserHaveGitInstallationAccess checks that a user has access to an installation id
|
|
|
+// by ensuring the installation id exists for one org or account they have access to
|
|
|
+// note that this makes a github API request, but the endpoint is fast so this doesn't add
|
|
|
+// much overhead
|
|
|
+func (auth *Auth) DoesUserHaveGitInstallationAccess(
|
|
|
next http.Handler,
|
|
|
projLoc IDLocation,
|
|
|
gitRepoLoc IDLocation,
|
|
|
@@ -405,46 +411,99 @@ func (auth *Auth) DoesUserHaveGitRepoAccess(
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
// TODO: needs to use new github integration implementation
|
|
|
|
|
|
- next.ServeHTTP(w, r)
|
|
|
-
|
|
|
- //grID, err := findGitRepoIDInRequest(r, gitRepoLoc)
|
|
|
- //
|
|
|
- //if err != nil {
|
|
|
- // http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
|
|
- // return
|
|
|
- //}
|
|
|
- //
|
|
|
- //projID, err := findProjIDInRequest(r, projLoc)
|
|
|
- //
|
|
|
- //if err != nil {
|
|
|
- // http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
|
|
- // return
|
|
|
- //}
|
|
|
- //
|
|
|
- //// get the service accounts belonging to the project
|
|
|
- //grs, err := auth.repo.GitRepo.ListGitReposByProjectID(uint(projID))
|
|
|
- //
|
|
|
- //if err != nil {
|
|
|
- // http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
|
- // return
|
|
|
- //}
|
|
|
- //
|
|
|
- //doesExist := false
|
|
|
- //
|
|
|
- //for _, gr := range grs {
|
|
|
- // if gr.ID == uint(grID) {
|
|
|
- // doesExist = true
|
|
|
- // break
|
|
|
- // }
|
|
|
- //}
|
|
|
- //
|
|
|
- //if doesExist {
|
|
|
- // next.ServeHTTP(w, r)
|
|
|
- // return
|
|
|
- //}
|
|
|
- //
|
|
|
- //http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
|
|
- //return
|
|
|
+ grID, err := findGitInstallationIDInRequest(r, gitRepoLoc)
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ tok := auth.getTokenFromRequest(r)
|
|
|
+
|
|
|
+ var userID uint
|
|
|
+
|
|
|
+ if tok != nil {
|
|
|
+ userID = tok.IBy
|
|
|
+ } else {
|
|
|
+ session, err := auth.store.Get(r, auth.cookieName)
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ sessionUserID, ok := session.Values["user_id"]
|
|
|
+ userID = sessionUserID.(uint)
|
|
|
+
|
|
|
+ if !ok {
|
|
|
+ http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ user, err := auth.repo.User.ReadUser(userID)
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ oauthInt, err := auth.repo.GithubAppOAuthIntegration.ReadGithubAppOauthIntegration(user.GithubAppIntegrationID)
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ client := github.NewClient(auth.GithubProjectConf.Client(oauth2.NoContext, &oauth2.Token{
|
|
|
+ AccessToken: string(oauthInt.AccessToken),
|
|
|
+ RefreshToken: string(oauthInt.RefreshToken),
|
|
|
+ TokenType: "Bearer",
|
|
|
+ }))
|
|
|
+
|
|
|
+ accountIDs := make([]int64, 0)
|
|
|
+
|
|
|
+ AuthUser, _, err := client.Users.Get(context.Background(), "")
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ accountIDs = append(accountIDs, *AuthUser.ID)
|
|
|
+
|
|
|
+ opts := &github.ListOptions{
|
|
|
+ PerPage: 100,
|
|
|
+ Page: 1,
|
|
|
+ }
|
|
|
+
|
|
|
+ for {
|
|
|
+ orgs, pages, err := client.Organizations.List(context.Background(), "", opts)
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, org := range orgs {
|
|
|
+ accountIDs = append(accountIDs, *org.ID)
|
|
|
+ }
|
|
|
+
|
|
|
+ if pages.NextPage == 0 {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ installations, err := auth.repo.GithubAppInstallation.ReadGithubAppInstallationByAccountIDs(accountIDs)
|
|
|
+
|
|
|
+ for _, installation := range installations {
|
|
|
+ if uint64(installation.InstallationID) == grID {
|
|
|
+ next.ServeHTTP(w, r)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
|
|
})
|
|
|
}
|
|
|
|
|
|
@@ -942,12 +1001,13 @@ func findRegistryIDInRequest(r *http.Request, registryLoc IDLocation) (uint64, e
|
|
|
return regID, nil
|
|
|
}
|
|
|
|
|
|
-func findGitRepoIDInRequest(r *http.Request, gitRepoLoc IDLocation) (uint64, error) {
|
|
|
+// findGitInstallationIDInRequest extracts and installation ID from a request
|
|
|
+func findGitInstallationIDInRequest(r *http.Request, gitRepoLoc IDLocation) (uint64, error) {
|
|
|
var grID uint64
|
|
|
var err error
|
|
|
|
|
|
if gitRepoLoc == URLParam {
|
|
|
- grID, err = strconv.ParseUint(chi.URLParam(r, "git_repo_id"), 0, 64)
|
|
|
+ grID, err = strconv.ParseUint(chi.URLParam(r, "installation_id"), 0, 64)
|
|
|
|
|
|
if err != nil {
|
|
|
return 0, err
|
|
|
@@ -977,10 +1037,10 @@ func findGitRepoIDInRequest(r *http.Request, gitRepoLoc IDLocation) (uint64, err
|
|
|
return 0, err
|
|
|
}
|
|
|
|
|
|
- if regStrArr, ok := vals["git_repo_id"]; ok && len(regStrArr) == 1 {
|
|
|
+ if regStrArr, ok := vals["installation_id"]; ok && len(regStrArr) == 1 {
|
|
|
grID, err = strconv.ParseUint(regStrArr[0], 10, 64)
|
|
|
} else {
|
|
|
- return 0, errors.New("git repo id not found")
|
|
|
+ return 0, errors.New("git app installation id not found")
|
|
|
}
|
|
|
}
|
|
|
|