Explorar el Código

Added github as external login method

AY hace 4 años
padre
commit
b3d5f92b71

+ 1 - 2
go.mod

@@ -5,7 +5,7 @@ go 1.13
 require (
 	github.com/andybalholm/brotli v1.0.0 // indirect
 	github.com/boltdb/bolt v1.3.1
-	github.com/brutella/hc v1.2.4 // indirect
+	github.com/brutella/hc v1.2.4
 	github.com/dhowden/tag v0.0.0-20200828214007-46e57f75dbfc
 	github.com/disintegration/imaging v1.6.2
 	github.com/fclairamb/ftpserverlib v0.8.0
@@ -41,7 +41,6 @@ require (
 	gitlab.com/NebulousLabs/go-upnp v0.0.0-20181011194642-3a71999ed0d3
 	golang.org/x/net v0.0.0-20210119194325-5f4716e94777
 	golang.org/x/oauth2 v0.0.0-20210615190721-d04028783cf1
-	golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect
 	golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
 	golang.org/x/text v0.3.3 // indirect
 	gopkg.in/sourcemap.v1 v1.0.5 // indirect

+ 83 - 0
mod/auth/oauth2/github.go

@@ -0,0 +1,83 @@
+package oauth2
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"time"
+
+	"golang.org/x/oauth2"
+	"golang.org/x/oauth2/github"
+)
+
+type GithubField struct {
+	Login                   string      `json:"login"`
+	ID                      int         `json:"id"`
+	NodeID                  string      `json:"node_id"`
+	AvatarURL               string      `json:"avatar_url"`
+	GravatarID              string      `json:"gravatar_id"`
+	URL                     string      `json:"url"`
+	HTMLURL                 string      `json:"html_url"`
+	FollowersURL            string      `json:"followers_url"`
+	FollowingURL            string      `json:"following_url"`
+	GistsURL                string      `json:"gists_url"`
+	StarredURL              string      `json:"starred_url"`
+	SubscriptionsURL        string      `json:"subscriptions_url"`
+	OrganizationsURL        string      `json:"organizations_url"`
+	ReposURL                string      `json:"repos_url"`
+	EventsURL               string      `json:"events_url"`
+	ReceivedEventsURL       string      `json:"received_events_url"`
+	Type                    string      `json:"type"`
+	SiteAdmin               bool        `json:"site_admin"`
+	Name                    string      `json:"name"`
+	Company                 string      `json:"company"`
+	Blog                    string      `json:"blog"`
+	Location                string      `json:"location"`
+	Email                   interface{} `json:"email"`
+	Hireable                interface{} `json:"hireable"`
+	Bio                     string      `json:"bio"`
+	TwitterUsername         interface{} `json:"twitter_username"`
+	PublicRepos             int         `json:"public_repos"`
+	PublicGists             int         `json:"public_gists"`
+	Followers               int         `json:"followers"`
+	Following               int         `json:"following"`
+	CreatedAt               time.Time   `json:"created_at"`
+	UpdatedAt               time.Time   `json:"updated_at"`
+	PrivateGists            int         `json:"private_gists"`
+	TotalPrivateRepos       int         `json:"total_private_repos"`
+	OwnedPrivateRepos       int         `json:"owned_private_repos"`
+	DiskUsage               int         `json:"disk_usage"`
+	Collaborators           int         `json:"collaborators"`
+	TwoFactorAuthentication bool        `json:"two_factor_authentication"`
+	Plan                    struct {
+		Name          string `json:"name"`
+		Space         int    `json:"space"`
+		Collaborators int    `json:"collaborators"`
+		PrivateRepos  int    `json:"private_repos"`
+	} `json:"plan"`
+}
+
+func githubScope() []string {
+	return []string{"read:user"}
+}
+
+func githubEndpoint() oauth2.Endpoint {
+	return github.Endpoint
+}
+
+func githubUserInfo(accessToken string) (string, error) {
+	client := &http.Client{}
+	req, err := http.NewRequest("GET", "https://api.github.com/user", nil)
+	req.Header.Set("Authorization", "token "+accessToken)
+	req.Header.Set("Accept", "application/vnd.github.v3+json")
+	response, err := client.Do(req)
+
+	defer response.Body.Close()
+	contents, err := ioutil.ReadAll(response.Body)
+	log.Println(string(contents))
+	var data GithubField
+	json.Unmarshal([]byte(contents), &data)
+
+	return data.Login + "@github.com", err
+}

+ 41 - 0
mod/auth/oauth2/google.go

@@ -0,0 +1,41 @@
+package oauth2
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"net/http"
+
+	"golang.org/x/oauth2"
+	"golang.org/x/oauth2/google"
+)
+
+type GoogleField struct {
+	ID            string `json:"id"`
+	Email         string `json:"email"`
+	VerifiedEmail bool   `json:"verified_email"`
+	Name          string `json:"name"`
+	GivenName     string `json:"given_name"`
+	FamilyName    string `json:"family_name"`
+	Picture       string `json:"picture"`
+	Locale        string `json:"locale"`
+}
+
+func googleScope() []string {
+	return []string{"https://www.googleapis.com/auth/userinfo.profile",
+		"https://www.googleapis.com/auth/userinfo.email"}
+}
+
+func googleEndpoint() oauth2.Endpoint {
+	return google.Endpoint
+}
+
+func googleUserInfo(accessToken string) (string, error) {
+	response, err := http.Get("https://www.googleapis.com/oauth2/v2/userinfo?access_token=" + accessToken)
+
+	defer response.Body.Close()
+	contents, err := ioutil.ReadAll(response.Body)
+	var data GoogleField
+	json.Unmarshal([]byte(contents), &data)
+
+	return data.Email, err
+}

+ 9 - 29
mod/auth/oauth2/oauth2.go

@@ -2,14 +2,12 @@ package oauth2
 
 import (
 	"encoding/json"
-	"io/ioutil"
 	"log"
 	"net/http"
 	"strconv"
 	"time"
 
 	"golang.org/x/oauth2"
-	"golang.org/x/oauth2/google"
 	auth "imuslab.com/arozos/mod/auth"
 	syncdb "imuslab.com/arozos/mod/auth/oauth2/syncdb"
 	reg "imuslab.com/arozos/mod/auth/register"
@@ -27,17 +25,6 @@ type OauthHandler struct {
 	config            *Config
 }
 
-type GoogleField struct {
-	ID            string `json:"id"`
-	Email         string `json:"email"`
-	VerifiedEmail bool   `json:"verified_email"`
-	Name          string `json:"name"`
-	GivenName     string `json:"given_name"`
-	FamilyName    string `json:"family_name"`
-	Picture       string `json:"picture"`
-	Locale        string `json:"locale"`
-}
-
 type Config struct {
 	Enabled          bool   `json:"enabled"`
 	IDP              string `json:"idp"`
@@ -60,9 +47,8 @@ func NewOauthHandler(authAgent *auth.AuthAgent, register *reg.RegisterHandler, c
 			RedirectURL:  readSingleConfig("redirecturl", coreDb) + "/system/auth/oauth/authorize",
 			ClientID:     readSingleConfig("clientid", coreDb),
 			ClientSecret: readSingleConfig("clientsecret", coreDb),
-			Scopes: []string{"https://www.googleapis.com/auth/userinfo.profile",
-				"https://www.googleapis.com/auth/userinfo.email"},
-			Endpoint: google.Endpoint,
+			Scopes:       getScope(coreDb),
+			Endpoint:     getEndpoint(coreDb),
 		},
 		DefaultUserGroup: readSingleConfig("defaultusergroup", coreDb),
 		ag:               authAgent,
@@ -111,24 +97,19 @@ func (oh *OauthHandler) HandleAuthorize(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	response, err := http.Get("https://www.googleapis.com/oauth2/v2/userinfo?access_token=" + token.AccessToken)
-
-	defer response.Body.Close()
-	contents, err := ioutil.ReadAll(response.Body)
-	var data GoogleField
-	json.Unmarshal([]byte(contents), &data)
+	username, err := getUserInfo(token.AccessToken, oh.coredb)
 
-	if !oh.ag.UserExists(data.Email) {
+	if !oh.ag.UserExists(username) {
 		//register user if not already exists
 		//random pwd to prevent ppl bypassing the OAuth handler
 		if oh.reg.AllowRegistry {
-			http.Redirect(w, r, "/public/register/register.system?user="+data.Email, 302)
+			http.Redirect(w, r, "/public/register/register.system?user="+username, 302)
 		} else {
 			sendTextResponse(w, "You are not allowed to register in this system.&nbsp;<a href=\"/\">Back</a>")
 		}
 	} else {
-		log.Println(data.Email + " logged in via OAuth.")
-		oh.ag.LoginUserByRequest(w, r, data.Email, true)
+		log.Println(username + " logged in via OAuth.")
+		oh.ag.LoginUserByRequest(w, r, username, true)
 		//clear the cooke
 		oh.addCookie(w, "uuid_login", "-invaild-", -1)
 		//read the value from db and delete it from db
@@ -219,9 +200,8 @@ func (oh *OauthHandler) WriteConfig(w http.ResponseWriter, r *http.Request) {
 		RedirectURL:  oh.readSingleConfig("redirecturl") + "/system/auth/oauth/authorize",
 		ClientID:     oh.readSingleConfig("clientid"),
 		ClientSecret: oh.readSingleConfig("clientsecret"),
-		Scopes: []string{"https://www.googleapis.com/auth/userinfo.profile",
-			"https://www.googleapis.com/auth/userinfo.email"},
-		Endpoint: google.Endpoint,
+		Scopes:       getScope(oh.coredb),
+		Endpoint:     getEndpoint(oh.coredb),
 	}
 
 	sendOK(w)

+ 38 - 0
mod/auth/oauth2/serviceSelector.go

@@ -0,0 +1,38 @@
+package oauth2
+
+import (
+	"errors"
+
+	"golang.org/x/oauth2"
+	db "imuslab.com/arozos/mod/database"
+)
+
+func getScope(coredb *db.Database) []string {
+	idp := readSingleConfig("idp", coredb)
+	if idp == "Google" {
+		return googleScope()
+	} else if idp == "Github" {
+		return githubScope()
+	}
+	return []string{}
+}
+
+func getEndpoint(coredb *db.Database) oauth2.Endpoint {
+	idp := readSingleConfig("idp", coredb)
+	if idp == "Google" {
+		return googleEndpoint()
+	} else if idp == "Github" {
+		return githubEndpoint()
+	}
+	return oauth2.Endpoint{}
+}
+
+func getUserInfo(accessToken string, coredb *db.Database) (string, error) {
+	idp := readSingleConfig("idp", coredb)
+	if idp == "Google" {
+		return googleUserInfo(accessToken)
+	} else if idp == "Github" {
+		return githubUserInfo(accessToken)
+	}
+	return "", errors.New("Unauthorized")
+}

+ 1 - 2
web/SystemAO/advance/oauth.html

@@ -154,8 +154,7 @@
 
         function loadIdpList() {
             $("#idplist").html("");
-            //var data = ["Google", "Microsoft", "Github"];
-            var data = ["Google"];
+            var data = ["Google", "Microsoft", "Github"];
             if (data.error !== undefined) {
                 alert(data.error);
             } else {