diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml
index e1de9143..7ad19d81 100644
--- a/.github/workflows/dev.yml
+++ b/.github/workflows/dev.yml
@@ -319,7 +319,7 @@ jobs:
dockerfile: Dockerfile.base
tags: "base"
- - name: Latest/Version Docker Image
+ - name: Dev Docker Image
uses: elgohr/Publish-Docker-Github-Action@master
env:
VERSION: ${{ env.VERSION }}
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index 0d3c67c0..7602ac04 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -5,10 +5,9 @@ on:
- '*' # matches every branch
- '*/*' # matches every branch containing a single '/'
- '!master' # excludes master
- - '!dev' # excludes dev
pull_request:
branches:
- - master
+ - dev
jobs:
compile:
diff --git a/frontend/src/forms/OAuth.vue b/frontend/src/forms/OAuth.vue
index 46933705..ec210e2e 100644
--- a/frontend/src/forms/OAuth.vue
+++ b/frontend/src/forms/OAuth.vue
@@ -46,6 +46,18 @@
+
@@ -172,6 +184,8 @@
oauth: {
gh_client_id: "",
gh_client_secret: "",
+ gh_users: "",
+ gh_orgs: "",
google_client_id: "",
google_client_secret: "",
oauth_domains: "",
diff --git a/handlers/oauth.go b/handlers/oauth.go
index 14f9bc40..3a7f7149 100644
--- a/handlers/oauth.go
+++ b/handlers/oauth.go
@@ -1,18 +1,12 @@
package handlers
import (
- "encoding/json"
"fmt"
"github.com/gorilla/mux"
"github.com/statping/statping/types/core"
"github.com/statping/statping/types/null"
"github.com/statping/statping/types/users"
- "github.com/statping/statping/utils"
- "golang.org/x/oauth2"
- "golang.org/x/oauth2/google"
- "golang.org/x/oauth2/slack"
"net/http"
- "time"
)
type oAuth struct {
@@ -63,87 +57,3 @@ func oauthLogin(oauth *oAuth, w http.ResponseWriter, r *http.Request) {
//returnJson(user, w, r)
http.Redirect(w, r, core.App.Domain+"/dashboard", http.StatusPermanentRedirect)
}
-
-func googleOAuth(r *http.Request) (*oAuth, error) {
- c := core.App
- code := r.URL.Query().Get("code")
-
- config := &oauth2.Config{
- ClientID: c.OAuth.GoogleClientID,
- ClientSecret: c.OAuth.GoogleClientSecret,
- Endpoint: google.Endpoint,
- }
-
- gg, err := config.Exchange(r.Context(), code)
- if err != nil {
- return nil, err
- }
-
- return &oAuth{
- Token: gg.AccessToken,
- RefreshToken: gg.RefreshToken,
- Valid: gg.Valid(),
- }, nil
-}
-
-func slackOAuth(r *http.Request) (*oAuth, error) {
- c := core.App
- code := r.URL.Query().Get("code")
-
- config := &oauth2.Config{
- ClientID: c.OAuth.SlackClientID,
- ClientSecret: c.OAuth.SlackClientSecret,
- Endpoint: slack.Endpoint,
- RedirectURL: c.Domain + basePath + "oauth/slack",
- Scopes: []string{"identity.basic"},
- }
-
- gg, err := config.Exchange(r.Context(), code)
- if err != nil {
- return nil, err
- }
-
- oauther := &oAuth{
- Token: gg.AccessToken,
- RefreshToken: gg.RefreshToken,
- Valid: gg.Valid(),
- Type: gg.Type(),
- }
-
- return oauther.slackIdentity()
-}
-
-// slackIdentity will query the Slack API to fetch the users ID, username, and email address.
-func (a *oAuth) slackIdentity() (*oAuth, error) {
- url := fmt.Sprintf("https://slack.com/api/users.identity?token=%s", a.Token)
- out, resp, err := utils.HttpRequest(url, "GET", "application/x-www-form-urlencoded", nil, nil, 10*time.Second, true, nil)
- if err != nil {
- return a, err
- }
- defer resp.Body.Close()
-
- var i *slackIdentity
- if err := json.Unmarshal(out, &i); err != nil {
- return a, err
- }
- a.Email = i.User.Email
- a.ID = i.User.ID
- a.Username = i.User.Name
- return a, nil
-}
-
-type slackIdentity struct {
- Ok bool `json:"ok"`
- User struct {
- Name string `json:"name"`
- ID string `json:"id"`
- Email string `json:"email"`
- } `json:"user"`
- Team struct {
- ID string `json:"id"`
- } `json:"team"`
-}
-
-func secureToken(w http.ResponseWriter, r *http.Request) {
-
-}
diff --git a/handlers/oauth_github.go b/handlers/oauth_github.go
index fb6a848a..9a9ac856 100644
--- a/handlers/oauth_github.go
+++ b/handlers/oauth_github.go
@@ -3,6 +3,7 @@ package handlers
import (
"encoding/json"
"github.com/statping/statping/types/core"
+ "github.com/statping/statping/types/errors"
"github.com/statping/statping/utils"
"golang.org/x/oauth2"
"golang.org/x/oauth2/github"
@@ -26,21 +27,20 @@ func githubOAuth(r *http.Request) (*oAuth, error) {
return nil, err
}
- headers := []string{
- "Accept=application/vnd.github.machine-man-preview+json",
- "Authorization=token " + gg.AccessToken,
- }
-
- resp, _, err := utils.HttpRequest("https://api.github.com/user", "GET", nil, headers, nil, 10*time.Second, true, nil)
+ user, err := returnGithubUser(gg.AccessToken)
if err != nil {
return nil, err
}
- var user githubUser
- if err := json.Unmarshal(resp, &user); err != nil {
+ orgs, err := returnGithubOrganizations(gg.AccessToken, user.Login)
+ if err != nil {
return nil, err
}
+ if allowed := validateGithub(user, orgs); !allowed {
+ return nil, errors.New("github user is not allowed to login")
+ }
+
return &oAuth{
Token: gg.AccessToken,
RefreshToken: gg.RefreshToken,
@@ -51,6 +51,80 @@ func githubOAuth(r *http.Request) (*oAuth, error) {
}, nil
}
+func returnGithubUser(token string) (githubUser, error) {
+ headers := []string{
+ "Accept=application/vnd.github.machine-man-preview+json",
+ "Authorization=token " + token,
+ }
+ resp, _, err := utils.HttpRequest("https://api.github.com/user", "GET", nil, headers, nil, 10*time.Second, true, nil)
+ if err != nil {
+ return githubUser{}, err
+ }
+ var user githubUser
+ if err := json.Unmarshal(resp, &user); err != nil {
+ return githubUser{}, err
+ }
+ return user, nil
+}
+
+func returnGithubOrganizations(token, username string) ([]githubOrgs, error) {
+ headers := []string{
+ "Accept=application/vnd.github.machine-man-preview+json",
+ "Authorization=token " + token,
+ }
+ resp, _, err := utils.HttpRequest("https://api.github.com/users/"+username+"/orgs", "GET", nil, headers, nil, 10*time.Second, true, nil)
+ if err != nil {
+ return nil, err
+ }
+ var orgs []githubOrgs
+ if err := json.Unmarshal(resp, &orgs); err != nil {
+ return nil, err
+ }
+ return orgs, nil
+}
+
+func validateGithub(ghUser githubUser, orgs []githubOrgs) bool {
+ auth := core.App.OAuth
+ if auth.GithubUsers == "" && auth.GithubOrgs == "" {
+ return true
+ }
+
+ if auth.GithubUsers != "" {
+ users := strings.Split(auth.GithubUsers, ",")
+ for _, u := range users {
+ if strings.ToLower(ghUser.Login) == strings.ToLower(u) {
+ return true
+ }
+ }
+ }
+ if auth.GithubOrgs != "" {
+ orgsAllowed := strings.Split(auth.GithubOrgs, ",")
+ for _, o := range orgsAllowed {
+ for _, org := range orgs {
+ if strings.ToLower(o) == strings.ToLower(org.Login) {
+ return true
+ }
+ }
+ }
+ }
+ return false
+}
+
+type githubOrgs struct {
+ Login string `json:"login"`
+ ID int `json:"id"`
+ NodeID string `json:"node_id"`
+ URL string `json:"url"`
+ ReposURL string `json:"repos_url"`
+ EventsURL string `json:"events_url"`
+ HooksURL string `json:"hooks_url"`
+ IssuesURL string `json:"issues_url"`
+ MembersURL string `json:"members_url"`
+ PublicMembersURL string `json:"public_members_url"`
+ AvatarURL string `json:"avatar_url"`
+ Description string `json:"description"`
+}
+
type githubUser struct {
Login string `json:"login"`
ID int `json:"id"`
diff --git a/handlers/oauth_google.go b/handlers/oauth_google.go
new file mode 100644
index 00000000..fb231716
--- /dev/null
+++ b/handlers/oauth_google.go
@@ -0,0 +1,30 @@
+package handlers
+
+import (
+ "github.com/statping/statping/types/core"
+ "golang.org/x/oauth2"
+ "golang.org/x/oauth2/google"
+ "net/http"
+)
+
+func googleOAuth(r *http.Request) (*oAuth, error) {
+ c := core.App
+ code := r.URL.Query().Get("code")
+
+ config := &oauth2.Config{
+ ClientID: c.OAuth.GoogleClientID,
+ ClientSecret: c.OAuth.GoogleClientSecret,
+ Endpoint: google.Endpoint,
+ }
+
+ gg, err := config.Exchange(r.Context(), code)
+ if err != nil {
+ return nil, err
+ }
+
+ return &oAuth{
+ Token: gg.AccessToken,
+ RefreshToken: gg.RefreshToken,
+ Valid: gg.Valid(),
+ }, nil
+}
diff --git a/handlers/oauth_slack.go b/handlers/oauth_slack.go
new file mode 100644
index 00000000..857065bf
--- /dev/null
+++ b/handlers/oauth_slack.go
@@ -0,0 +1,79 @@
+package handlers
+
+import (
+ "encoding/json"
+ "fmt"
+ "github.com/statping/statping/types/core"
+ "github.com/statping/statping/types/errors"
+ "github.com/statping/statping/utils"
+ "golang.org/x/oauth2"
+ "golang.org/x/oauth2/slack"
+ "net/http"
+ "time"
+)
+
+func slackOAuth(r *http.Request) (*oAuth, error) {
+ c := core.App
+ code := r.URL.Query().Get("code")
+
+ config := &oauth2.Config{
+ ClientID: c.OAuth.SlackClientID,
+ ClientSecret: c.OAuth.SlackClientSecret,
+ Endpoint: slack.Endpoint,
+ RedirectURL: c.Domain + basePath + "oauth/slack",
+ Scopes: []string{"identity.basic"},
+ }
+
+ gg, err := config.Exchange(r.Context(), code)
+ if err != nil {
+ return nil, err
+ }
+
+ oauther := &oAuth{
+ Token: gg.AccessToken,
+ RefreshToken: gg.RefreshToken,
+ Valid: gg.Valid(),
+ Type: gg.Type(),
+ }
+
+ identity, err := returnSlackIdentity(gg.AccessToken)
+ if err != nil {
+ return nil, err
+ }
+
+ if !identity.Ok {
+ return nil, errors.New("slack identity is invalid")
+ }
+
+ oauther.Username = identity.User.Name
+ oauther.Email = identity.User.Email
+
+ return oauther, nil
+}
+
+// slackIdentity will query the Slack API to fetch the users ID, username, and email address.
+func returnSlackIdentity(token string) (slackIdentity, error) {
+ url := fmt.Sprintf("https://slack.com/api/users.identity?token=%s", token)
+ out, _, err := utils.HttpRequest(url, "GET", "application/x-www-form-urlencoded", nil, nil, 10*time.Second, true, nil)
+ if err != nil {
+ return slackIdentity{}, err
+ }
+
+ var i slackIdentity
+ if err := json.Unmarshal(out, &i); err != nil {
+ return slackIdentity{}, err
+ }
+ return i, nil
+}
+
+type slackIdentity struct {
+ Ok bool `json:"ok"`
+ User struct {
+ Name string `json:"name"`
+ ID string `json:"id"`
+ Email string `json:"email"`
+ } `json:"user"`
+ Team struct {
+ ID string `json:"id"`
+ } `json:"team"`
+}
diff --git a/types/core/struct.go b/types/core/struct.go
index 6f52a482..88d51a13 100644
--- a/types/core/struct.go
+++ b/types/core/struct.go
@@ -47,11 +47,14 @@ type OAuth struct {
Providers string `gorm:"column:oauth_providers;" json:"oauth_providers"`
GithubClientID string `gorm:"column:gh_client_id" json:"gh_client_id"`
GithubClientSecret string `gorm:"column:gh_client_secret" json:"gh_client_secret" scope:"admin"`
+ GithubUsers string `gorm:"column:gh_users" json:"gh_users" scope:"admin"`
+ GithubOrgs string `gorm:"column:gh_orgs" json:"gh_orgs" scope:"admin"`
GoogleClientID string `gorm:"column:google_client_id" json:"google_client_id"`
GoogleClientSecret string `gorm:"column:google_client_secret" json:"google_client_secret" scope:"admin"`
+ GoogleUsers string `gorm:"column:google_users" json:"google_users" scope:"admin"`
SlackClientID string `gorm:"column:slack_client_id" json:"slack_client_id"`
SlackClientSecret string `gorm:"column:slack_client_secret" json:"slack_client_secret" scope:"admin"`
- SlackTeam string `gorm:"column:slack_team" json:"slack_team"`
+ SlackTeam string `gorm:"column:slack_team" json:"slack_team" scope:"admin"`
}
// AllNotifiers contains all the Notifiers loaded