Sfoglia il codice sorgente

Merge branch 'OAuth' of tmp/arozos into master

Login.system require a better implementation later. Merge for now
TC 4 anni fa
parent
commit
f3e5f78dca

+ 6 - 1
mod/auth/oauth2/github.go

@@ -68,10 +68,15 @@ func githubEndpoint() oauth2.Endpoint {
 func githubUserInfo(accessToken string) (string, error) {
 	client := &http.Client{}
 	req, err := http.NewRequest("GET", "https://api.github.com/user", nil)
+	if err != nil {
+		return "", err
+	}
 	req.Header.Set("Authorization", "token "+accessToken)
 	req.Header.Set("Accept", "application/vnd.github.v3+json")
 	response, err := client.Do(req)
-
+	if err != nil {
+		return "", err
+	}
 	defer response.Body.Close()
 	contents, err := ioutil.ReadAll(response.Body)
 	var data GithubField

+ 88 - 0
mod/auth/oauth2/gitlab.go

@@ -0,0 +1,88 @@
+package oauth2
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"time"
+
+	"golang.org/x/oauth2"
+)
+
+type GitlabField struct {
+	ID                             int           `json:"id"`
+	Name                           string        `json:"name"`
+	Username                       string        `json:"username"`
+	State                          string        `json:"state"`
+	AvatarURL                      string        `json:"avatar_url"`
+	WebURL                         string        `json:"web_url"`
+	CreatedAt                      time.Time     `json:"created_at"`
+	Bio                            string        `json:"bio"`
+	BioHTML                        string        `json:"bio_html"`
+	Location                       interface{}   `json:"location"`
+	PublicEmail                    string        `json:"public_email"`
+	Skype                          string        `json:"skype"`
+	Linkedin                       string        `json:"linkedin"`
+	Twitter                        string        `json:"twitter"`
+	WebsiteURL                     string        `json:"website_url"`
+	Organization                   interface{}   `json:"organization"`
+	JobTitle                       string        `json:"job_title"`
+	Pronouns                       interface{}   `json:"pronouns"`
+	Bot                            bool          `json:"bot"`
+	WorkInformation                interface{}   `json:"work_information"`
+	Followers                      int           `json:"followers"`
+	Following                      int           `json:"following"`
+	LastSignInAt                   time.Time     `json:"last_sign_in_at"`
+	ConfirmedAt                    time.Time     `json:"confirmed_at"`
+	LastActivityOn                 string        `json:"last_activity_on"`
+	Email                          string        `json:"email"`
+	ThemeID                        int           `json:"theme_id"`
+	ColorSchemeID                  int           `json:"color_scheme_id"`
+	ProjectsLimit                  int           `json:"projects_limit"`
+	CurrentSignInAt                time.Time     `json:"current_sign_in_at"`
+	Identities                     []interface{} `json:"identities"`
+	CanCreateGroup                 bool          `json:"can_create_group"`
+	CanCreateProject               bool          `json:"can_create_project"`
+	TwoFactorEnabled               bool          `json:"two_factor_enabled"`
+	External                       bool          `json:"external"`
+	PrivateProfile                 bool          `json:"private_profile"`
+	CommitEmail                    string        `json:"commit_email"`
+	SharedRunnersMinutesLimit      interface{}   `json:"shared_runners_minutes_limit"`
+	ExtraSharedRunnersMinutesLimit interface{}   `json:"extra_shared_runners_minutes_limit"`
+	IsAdmin                        bool          `json:"is_admin"`
+	Note                           interface{}   `json:"note"`
+	UsingLicenseSeat               bool          `json:"using_license_seat"`
+}
+
+func gitlabScope() []string {
+	return []string{"read_user api read_api"}
+}
+
+func gitlabEndpoint(server string) oauth2.Endpoint {
+	Endpoint := oauth2.Endpoint{
+		AuthURL:  server + "/oauth/authorize",
+		TokenURL: server + "/oauth/token",
+	}
+	return Endpoint
+}
+
+func gitlabUserInfo(accessToken string, server string) (string, error) {
+	response, err := http.Get(server + "/api/v4/user?access_token=" + accessToken)
+	if err != nil {
+		return "", err
+	}
+	defer response.Body.Close()
+	contents, err := ioutil.ReadAll(response.Body)
+	if err != nil {
+		return "", err
+	}
+	var data GitlabField
+	json.Unmarshal([]byte(contents), &data)
+
+	serverURL, err := url.Parse(server)
+	if err != nil {
+		return "", err
+	}
+	return data.Username + "@" + serverURL.Hostname(), err
+}

+ 3 - 1
mod/auth/oauth2/google.go

@@ -31,7 +31,9 @@ func googleEndpoint() oauth2.Endpoint {
 
 func googleUserInfo(accessToken string) (string, error) {
 	response, err := http.Get("https://www.googleapis.com/oauth2/v2/userinfo?access_token=" + accessToken)
-
+	if err != nil {
+		return "", err
+	}
 	defer response.Body.Close()
 	contents, err := ioutil.ReadAll(response.Body)
 	var data GoogleField

+ 1 - 1
mod/auth/oauth2/internal.go

@@ -33,7 +33,7 @@ func sendOK(w http.ResponseWriter) {
 }
 
 func mv(r *http.Request, getParamter string, postMode bool) (string, error) {
-	if postMode == false {
+	if !postMode {
 		//Access the paramter via GET
 		keys, ok := r.URL.Query()[getParamter]
 

+ 6 - 1
mod/auth/oauth2/microsoft.go

@@ -31,9 +31,14 @@ func microsoftEndpoint() oauth2.Endpoint {
 func microsoftUserInfo(accessToken string) (string, error) {
 	client := &http.Client{}
 	req, err := http.NewRequest("GET", "https://graph.microsoft.com/oidc/userinfo", nil)
+	if err != nil {
+		return "", err
+	}
 	req.Header.Set("Authorization", "Bearer "+accessToken)
 	response, err := client.Do(req)
-
+	if err != nil {
+		return "", err
+	}
 	defer response.Body.Close()
 	contents, err := ioutil.ReadAll(response.Body)
 	var data MicrosoftField

+ 117 - 48
mod/auth/oauth2/oauth2.go

@@ -1,6 +1,7 @@
 package oauth2
 
 import (
+	"context"
 	"encoding/json"
 	"log"
 	"net/http"
@@ -17,21 +18,19 @@ import (
 type OauthHandler struct {
 	googleOauthConfig *oauth2.Config
 	syncDb            *syncdb.SyncDB
-	oauthStateString  string
-	DefaultUserGroup  string
 	ag                *auth.AuthAgent
 	reg               *reg.RegisterHandler
 	coredb            *db.Database
-	config            *Config
 }
 
 type Config struct {
-	Enabled          bool   `json:"enabled"`
-	IDP              string `json:"idp"`
-	RedirectURL      string `json:"redirect_url"`
-	ClientID         string `json:"client_id"`
-	ClientSecret     string `json:"client_secret"`
-	DefaultUserGroup string `json:"default_user_group"`
+	Enabled      bool   `json:"enabled"`
+	AutoRedirect bool   `json:"auto_redirect"`
+	IDP          string `json:"idp"`
+	RedirectURL  string `json:"redirect_url"`
+	ServerURL    string `json:"server_url"`
+	ClientID     string `json:"client_id"`
+	ClientSecret string `json:"client_secret"`
 }
 
 //NewOauthHandler xxx
@@ -50,11 +49,10 @@ func NewOauthHandler(authAgent *auth.AuthAgent, register *reg.RegisterHandler, c
 			Scopes:       getScope(coreDb),
 			Endpoint:     getEndpoint(coreDb),
 		},
-		DefaultUserGroup: readSingleConfig("defaultusergroup", coreDb),
-		ag:               authAgent,
-		syncDb:           syncdb.NewSyncDB(),
-		reg:              register,
-		coredb:           coreDb,
+		ag:     authAgent,
+		syncDb: syncdb.NewSyncDB(),
+		reg:    register,
+		coredb: coreDb,
 	}
 
 	return &NewlyCreatedOauthHandler
@@ -62,14 +60,21 @@ func NewOauthHandler(authAgent *auth.AuthAgent, register *reg.RegisterHandler, c
 
 //HandleOauthLogin xxx
 func (oh *OauthHandler) HandleLogin(w http.ResponseWriter, r *http.Request) {
+	enabled := oh.readSingleConfig("enabled")
+	if enabled == "" || enabled == "false" {
+		sendTextResponse(w, "OAuth disabled")
+		return
+	}
 	//add cookies
-	redirect, e := r.URL.Query()["redirect"]
+	redirect, err := mv(r, "redirect", false)
+	//store the redirect url to the sync map
 	uuid := ""
-	if !e || len(redirect[0]) < 1 {
+	if err != nil {
 		uuid = oh.syncDb.Store("/")
 	} else {
-		uuid = oh.syncDb.Store(redirect[0])
+		uuid = oh.syncDb.Store(redirect)
 	}
+	//store the key to client
 	oh.addCookie(w, "uuid_login", uuid, 30*time.Minute)
 	//handle redirect
 	url := oh.googleOauthConfig.AuthCodeURL(uuid)
@@ -78,6 +83,11 @@ func (oh *OauthHandler) HandleLogin(w http.ResponseWriter, r *http.Request) {
 
 //OauthAuthorize xxx
 func (oh *OauthHandler) HandleAuthorize(w http.ResponseWriter, r *http.Request) {
+	enabled := oh.readSingleConfig("enabled")
+	if enabled == "" || enabled == "false" {
+		sendTextResponse(w, "OAuth disabled")
+		return
+	}
 	//read the uuid(aka the state parameter)
 	uuid, err := r.Cookie("uuid_login")
 	if err != nil {
@@ -85,52 +95,85 @@ func (oh *OauthHandler) HandleAuthorize(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	state := r.FormValue("state")
+	state, err := mv(r, "state", true)
 	if state != uuid.Value {
 		sendTextResponse(w, "Invalid oauth state.")
 		return
 	}
+	if err != nil {
+		sendTextResponse(w, "Invalid state parameter.")
+		return
+	}
 
-	code := r.FormValue("code")
-	token, err := oh.googleOauthConfig.Exchange(oauth2.NoContext, code)
+	code, err := mv(r, "code", true)
+	if err != nil {
+		sendTextResponse(w, "Invalid state parameter.")
+		return
+	}
+
+	//exchange the infromation to get code
+	token, err := oh.googleOauthConfig.Exchange(context.Background(), code)
 	if err != nil {
 		sendTextResponse(w, "Code exchange failed.")
 		return
 	}
 
+	//get user info
 	username, err := getUserInfo(token.AccessToken, oh.coredb)
 	if err != nil {
+		oh.ag.Logger.LogAuthByRequestInfo(username, r.RemoteAddr, time.Now().Unix(), false, "web")
 		sendTextResponse(w, "Failed to obtain user info.")
 		return
 	}
 
 	if !oh.ag.UserExists(username) {
 		//register user if not already exists
-		//random pwd to prevent ppl bypassing the OAuth handler
+		//if registration is closed, return error message.
+		//also makr the login as fail.
 		if oh.reg.AllowRegistry {
-			http.Redirect(w, r, "/public/register/register.system?user="+username, 302)
+			oh.ag.Logger.LogAuthByRequestInfo(username, r.RemoteAddr, time.Now().Unix(), false, "web")
+			http.Redirect(w, r, "/public/register/register.system?user="+username, http.StatusFound)
 		} else {
+			oh.ag.Logger.LogAuthByRequestInfo(username, r.RemoteAddr, time.Now().Unix(), false, "web")
 			sendHTMLResponse(w, "You are not allowed to register in this system.&nbsp;<a href=\"/\">Back</a>")
 		}
 	} else {
 		log.Println(username + " logged in via OAuth.")
 		oh.ag.LoginUserByRequest(w, r, username, true)
+		oh.ag.Logger.LogAuthByRequestInfo(username, r.RemoteAddr, time.Now().Unix(), true, "web")
 		//clear the cooke
 		oh.addCookie(w, "uuid_login", "-invaild-", -1)
 		//read the value from db and delete it from db
 		url := oh.syncDb.Read(uuid.Value)
 		oh.syncDb.Delete(uuid.Value)
 		//redirect to the desired page
-		http.Redirect(w, r, url, 302)
+		http.Redirect(w, r, url, http.StatusFound)
 	}
 }
 
+//CheckOAuth check if oauth is enabled
 func (oh *OauthHandler) CheckOAuth(w http.ResponseWriter, r *http.Request) {
+	enabledB := false
 	enabled := oh.readSingleConfig("enabled")
-	if enabled == "" {
-		enabled = "false"
+	if enabled == "true" {
+		enabledB = true
+	}
+
+	autoredirectB := false
+	autoredirect := oh.readSingleConfig("autoredirect")
+	if autoredirect == "true" {
+		autoredirectB = true
+	}
+
+	type returnFormat struct {
+		Enabled      bool `json:"enabled"`
+		AutoRedirect bool `json:"auto_redirect"`
+	}
+	json, err := json.Marshal(returnFormat{Enabled: enabledB, AutoRedirect: autoredirectB})
+	if err != nil {
+		sendErrorResponse(w, "Error occurred while marshalling JSON response")
 	}
-	sendJSONResponse(w, enabled)
+	sendJSONResponse(w, string(json))
 }
 
 //https://golangcode.com/add-a-http-cookie/
@@ -145,23 +188,36 @@ func (oh *OauthHandler) addCookie(w http.ResponseWriter, name, value string, ttl
 }
 
 func (oh *OauthHandler) ReadConfig(w http.ResponseWriter, r *http.Request) {
-	enabled, _ := strconv.ParseBool(oh.readSingleConfig("enabled"))
+	enabled, err := strconv.ParseBool(oh.readSingleConfig("enabled"))
+	if err != nil {
+		sendTextResponse(w, "Invalid config value [key=enabled].")
+		return
+	}
+	autoredirect, err := strconv.ParseBool(oh.readSingleConfig("autoredirect"))
+	if err != nil {
+		sendTextResponse(w, "Invalid config value [key=autoredirect].")
+		return
+	}
 	idp := oh.readSingleConfig("idp")
 	redirecturl := oh.readSingleConfig("redirecturl")
+	serverurl := oh.readSingleConfig("serverurl")
 	clientid := oh.readSingleConfig("clientid")
 	clientsecret := oh.readSingleConfig("clientsecret")
-	defaultusergroup := oh.readSingleConfig("defaultusergroup")
 
 	config, err := json.Marshal(Config{
-		Enabled:          enabled,
-		IDP:              idp,
-		RedirectURL:      redirecturl,
-		ClientID:         clientid,
-		ClientSecret:     clientsecret,
-		DefaultUserGroup: defaultusergroup,
+		Enabled:      enabled,
+		AutoRedirect: autoredirect,
+		IDP:          idp,
+		ServerURL:    serverurl,
+		RedirectURL:  redirecturl,
+		ClientID:     clientid,
+		ClientSecret: clientsecret,
 	})
 	if err != nil {
-		empty, _ := json.Marshal(Config{})
+		empty, err := json.Marshal(Config{})
+		if err != nil {
+			sendErrorResponse(w, "Error while marshalling config")
+		}
 		sendJSONResponse(w, string(empty))
 	}
 	sendJSONResponse(w, string(config))
@@ -170,11 +226,14 @@ func (oh *OauthHandler) ReadConfig(w http.ResponseWriter, r *http.Request) {
 func (oh *OauthHandler) WriteConfig(w http.ResponseWriter, r *http.Request) {
 	enabled, err := mv(r, "enabled", true)
 	if err != nil {
-		sendErrorResponse(w, "enabled field can't be empty'")
+		sendErrorResponse(w, "enabled field can't be empty")
+		return
+	}
+	autoredirect, err := mv(r, "autoredirect", true)
+	if err != nil {
+		sendErrorResponse(w, "enabled field can't be empty")
 		return
 	}
-
-	oh.coredb.Write("oauth", "enabled", enabled)
 
 	showError := true
 	if enabled != "true" {
@@ -184,44 +243,54 @@ func (oh *OauthHandler) WriteConfig(w http.ResponseWriter, r *http.Request) {
 	idp, err := mv(r, "idp", true)
 	if err != nil {
 		if showError {
-			sendErrorResponse(w, "idp field can't be empty'")
+			sendErrorResponse(w, "idp field can't be empty")
 			return
 		}
 	}
 	redirecturl, err := mv(r, "redirecturl", true)
 	if err != nil {
 		if showError {
-			sendErrorResponse(w, "redirecturl field can't be empty'")
+			sendErrorResponse(w, "redirecturl field can't be empty")
 			return
 		}
 	}
-	clientid, err := mv(r, "clientid", true)
+	serverurl, err := mv(r, "serverurl", true)
 	if err != nil {
 		if showError {
-			sendErrorResponse(w, "clientid field can't be empty'")
-			return
+			if idp != "Gitlab" {
+				serverurl = ""
+			} else {
+				sendErrorResponse(w, "serverurl field can't be empty")
+				return
+			}
 		}
 	}
-	clientsecret, err := mv(r, "clientsecret", true)
+	if idp != "Gitlab" {
+		serverurl = ""
+	}
+
+	clientid, err := mv(r, "clientid", true)
 	if err != nil {
 		if showError {
-			sendErrorResponse(w, "clientsecret field can't be empty'")
+			sendErrorResponse(w, "clientid field can't be empty")
 			return
 		}
 	}
-	defaultusergroup, err := mv(r, "defaultusergroup", true)
+	clientsecret, err := mv(r, "clientsecret", true)
 	if err != nil {
 		if showError {
-			sendErrorResponse(w, "defaultusergroup field can't be empty'")
+			sendErrorResponse(w, "clientsecret field can't be empty")
 			return
 		}
 	}
 
+	oh.coredb.Write("oauth", "enabled", enabled)
+	oh.coredb.Write("oauth", "autoredirect", autoredirect)
 	oh.coredb.Write("oauth", "idp", idp)
 	oh.coredb.Write("oauth", "redirecturl", redirecturl)
+	oh.coredb.Write("oauth", "serverurl", serverurl)
 	oh.coredb.Write("oauth", "clientid", clientid)
 	oh.coredb.Write("oauth", "clientsecret", clientsecret)
-	oh.coredb.Write("oauth", "defaultusergroup", defaultusergroup)
 
 	//update the information inside the oauth class
 	oh.googleOauthConfig = &oauth2.Config{

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

@@ -7,6 +7,7 @@ import (
 	db "imuslab.com/arozos/mod/database"
 )
 
+//getScope use to select the correct scope
 func getScope(coredb *db.Database) []string {
 	idp := readSingleConfig("idp", coredb)
 	if idp == "Google" {
@@ -15,10 +16,13 @@ func getScope(coredb *db.Database) []string {
 		return githubScope()
 	} else if idp == "Microsoft" {
 		return microsoftScope()
+	} else if idp == "Gitlab" {
+		return gitlabScope()
 	}
 	return []string{}
 }
 
+//getEndpoint use to select the correct endpoint
 func getEndpoint(coredb *db.Database) oauth2.Endpoint {
 	idp := readSingleConfig("idp", coredb)
 	if idp == "Google" {
@@ -27,10 +31,13 @@ func getEndpoint(coredb *db.Database) oauth2.Endpoint {
 		return githubEndpoint()
 	} else if idp == "Microsoft" {
 		return microsoftEndpoint()
+	} else if idp == "Gitlab" {
+		return gitlabEndpoint(readSingleConfig("serverurl", coredb))
 	}
 	return oauth2.Endpoint{}
 }
 
+//getUserinfo use to select the correct way to retrieve userinfo
 func getUserInfo(accessToken string, coredb *db.Database) (string, error) {
 	idp := readSingleConfig("idp", coredb)
 	if idp == "Google" {
@@ -39,6 +46,8 @@ func getUserInfo(accessToken string, coredb *db.Database) (string, error) {
 		return githubUserInfo(accessToken)
 	} else if idp == "Microsoft" {
 		return microsoftUserInfo(accessToken)
+	} else if idp == "Gitlab" {
+		return gitlabUserInfo(accessToken, readSingleConfig("serverurl", coredb))
 	}
 	return "", errors.New("Unauthorized")
 }

+ 2 - 2
mod/auth/oauth2/syncdb/syncdb.go

@@ -23,11 +23,11 @@ func NewSyncDB() *SyncDB {
 	//Put the newly craeted syncmap into the db object
 	newSyncDB := SyncDB{db: &newDB} //!!! USE POINTER HERE INSTEAD OF THE SYNC MAP ITSELF
 	//Return the pointer of the new SyncDB object
-	newSyncDB.AutoClening()
+	newSyncDB.AutoCleaning()
 	return &newSyncDB
 }
 
-func (p SyncDB) AutoClening() {
+func (p SyncDB) AutoCleaning() {
 	//create the routine for auto clean trash
 	go func() {
 		for {

+ 43 - 31
web/SystemAO/advance/oauth.html

@@ -79,6 +79,12 @@
                     <label>Enable OAuth</label>
                 </div>
             </div>
+            <div class="field">
+                <div class="ui toggle checkbox">
+                    <input type="checkbox" id="autoredirect" name="autoredirect">
+                    <label>Auto redirect</label>
+                </div>
+            </div>
             <div class="field">
                 <label>Select OAuth IdP (aka Service provider)</label>
                 <div class="ui selection fluid dropdown" autocomplete="false">
@@ -91,11 +97,17 @@
                 </div>
             </div>
             <div class="field">
-                <label>Redirect URL (you have to provide https://YOUR_DOMAIN/system/auth/oauth/authorize at the 3rd auth rely)</label>
+                <label>Redirect URL (you have to provide <span id="redirectspan">https://YOUR_DOMAIN/system/auth/oauth/authorize</span> at the 3rd auth rely)</label>
                 <div class="ui fluid input">
                     <input type="text" id="redirecturl" placeholder="https://YOUR_DOMAIN/">
                 </div>
             </div>
+            <div class="field" id="server" style="display: none;">
+                <label>Server URL</label>
+                <div class="ui fluid input">
+                    <input type="text" id="serverurl" placeholder="http://YOUR_DOMAIN/">
+                </div>
+            </div>
             <div class="field">
                 <label>Client ID</label>
                 <div class="ui fluid input">
@@ -108,17 +120,6 @@
                     <input type="text" id="clientsecret" placeholder="Client Secret">
                 </div>
             </div>
-            <div class="field">
-                <label>Default user group</label>
-                <div class="ui selection fluid dropdown" autocomplete="false">
-                    <input type="hidden" id="group" name="group" autocomplete="false">
-                    <i class="dropdown icon"></i>
-                    <div class="default text">Select user group</div>
-                    <div id="grouplist" class="menu">
-
-                    </div>
-                </div>
-            </div>
             <button id="ntb" onclick="update();" class="ui green button" type="submit">Update</button>
         </div>
         <div class="ui divider"></div>
@@ -129,8 +130,24 @@
     <script>
         $(document).ready(function() {
             loadIdpList();
-            loadGroupList();
             read();
+            initPlaceholder();
+        });
+
+        $("#idp").change(function() {
+            if ($("#idp").val() == "Gitlab") {
+                $("#server").removeAttr("style");
+            } else {
+                $("#server").attr("style", "display:none;");
+            }
+        });
+
+        $("#redirecturl").on('input propertychange', function() {
+            if ($("#redirecturl").val() == "") {
+                $("#redirectspan").text(window.location.origin + "/system/auth/oauth/authorize");
+            } else {
+                $("#redirectspan").text($("#redirecturl").val() + "/system/auth/oauth/authorize");
+            }
         });
 
         function read() {
@@ -138,27 +155,31 @@
                 if (data.enabled) {
                     $("#enable").parent().checkbox("check")
                 }
+                if (data.autoredirect) {
+                    $("#autoredirect").parent().checkbox("check")
+                }
                 $("#idp").parent().dropdown("set selected", data.idp);
+                $("#serverurl").val(data.server_url);
                 $("#redirecturl").val(data.redirect_url);
                 $("#clientid").val(data.client_id);
                 $("#clientsecret").val(data.client_secret);
-                $("#group").parent().dropdown("set selected", data.default_user_group);
             });
         }
 
         function update() {
             $.post("../../system/auth/oauth/config/write", {
                     enabled: $("#enable").parent().checkbox("is checked"),
+                    autoredirect: $("#autoredirect").parent().checkbox("is checked"),
                     idp: $("#idp").val(),
                     redirecturl: $("#redirecturl").val(),
                     clientid: $("#clientid").val(),
                     clientsecret: $("#clientsecret").val(),
-                    defaultusergroup: $("#group").val()
+                    serverurl: $("#serverurl").val()
                 })
                 .done(function(data) {
-                    if (data.error != undefined){
+                    if (data.error != undefined) {
                         alert(data.error);
-                    }else{
+                    } else {
                         //OK!
                         $("#updateSet").stop().finish().slideDown("fast").delay(3000).slideUp('fast');
                     }
@@ -167,7 +188,7 @@
 
         function loadIdpList() {
             $("#idplist").html("");
-            var data = ["Google", "Microsoft", "Github"];
+            var data = ["Google", "Microsoft", "Github", "Gitlab"];
             if (data.error !== undefined) {
                 alert(data.error);
             } else {
@@ -179,19 +200,10 @@
             $("#idplist").parent().dropdown();
         }
 
-        function loadGroupList() {
-            $("#grouplist").html("");
-            $.get("../../system/permission/listgroup", function(data) {
-                if (data.error !== undefined) {
-                    alert(data.error);
-                } else {
-                    for (var i = 0; i < data.length; i++) {
-                        let groupinfo = data[i];
-                        $("#grouplist").append(`<div class="item" data-value="${groupinfo}">${groupinfo}</div>`);
-                    }
-                }
-                $("#grouplist").parent().dropdown();
-            });
+        function initPlaceholder() {
+            $("#redirectspan").text(window.location.origin + "/system/auth/oauth/authorize");
+            $("#redirecturl").attr("placeholder", window.location.origin);
+            $("#serverurl").attr("placeholder", "https://gitlab.com");
         }
     </script>
 </body>

+ 29 - 3
web/login.system

@@ -122,6 +122,7 @@
     <script>
         var redirectionAddress = "{{redirection_addr}}";
         var systemUserCount = "{{usercount}}" - 0; //Magic way to convert string to int :)
+        var autoRedirectTimer;
         var isMobile = false; //initiate as false
         // device detection
         if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent) 
@@ -178,15 +179,34 @@
             });
 
             //OAuth related code, check if system is open for ext login
-            $.get("system/auth/oauth/checkoauth",function(data){
-                if (data == true){
+            $.getJSON("system/auth/oauth/checkoauth",function(data){
+                if (data.enabled == true){
                     $(".signin").show();
                 }else{
                     $(".signin").remove();
                 }
+                //if auto redirect is on
+                if(data.auto_redirect == true) {
+                    //checking if they come from desktop.system or mobile.system
+                    //if they come from that two pages, usually mean they are just logged out.
+                    if(document.referrer != ''){
+                        var path = new URL(document.referrer);
+                    } else {
+                        var path = new URL('http://0.0.0.0');
+
+                    }
+                    if(document.referrer != window.location.origin + "/desktop.system" && document.referrer != window.location.origin + "/mobile.system" && path.origin + path.pathname !=  window.location.origin + "/system/auth/oauth/authorize"){
+                        $(".ts.borderless.basic.segment").attr("style","display: none;");
+                        $(".ts.borderless.basic.segment").attr("id","aoLogin");
+                        $(".ts.borderless.basic.segment").after('<div id="autoRedirectSegment" class="ts borderless basic segment"><p><i class="key icon"></i>Redirecting to your organization sign in page...</p><br><a style="cursor: pointer;" onclick="stopAutoRedirect()">Cancel</a></div>');
+                        autoRedirectTimer = setTimeout(function(){
+                            window.location.href = "system/auth/oauth/login?redirect=" + redirectionAddress;
+                        }, 3000);
+                    }
+                }
             });
             if(get('redirect') != undefined){
-                $(".section.signin").attr("href","system/auth/oauth/login?redirect=" + get('redirect'));
+                $(".section.signin").attr("href","system/auth/oauth/login?redirect=" + redirectionAddress);
             }
 
             //Get the system hostname and replace the hostname fields
@@ -245,6 +265,12 @@
                 return decodeURIComponent(name[1]);
         }
 
+        function stopAutoRedirect(){
+            clearTimeout(autoRedirectTimer);
+            $("#aoLogin").removeAttr("style");
+            $("#autoRedirectSegment").attr("style", "display:none");
+        }
+
         $(".thisyear").text(new Date().getFullYear());
     </script>
     </body>