package oauth2 import ( "encoding/json" "io/ioutil" "log" "net/http" "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" ) type OauthHandler struct { googleOauthConfig *oauth2.Config syncDb *syncdb.SyncDB oauthStateString string DefaultUserGroup string ag *auth.AuthAgent reg *reg.RegisterHandler } 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"` } //NewOauthHandler xxx func NewOauthHandler(authAgent *auth.AuthAgent, register *reg.RegisterHandler) *OauthHandler { NewlyCreatedOauthHandler := OauthHandler{ googleOauthConfig: &oauth2.Config{ RedirectURL: "http://localhost:8080/system/auth/oauth/authorize", ClientID: "682431817920-nkmfn7m6uq0qbdo00hr2944m6r3hj8ua.apps.googleusercontent.com", ClientSecret: "Obdlr2S5n8rj_qwsPLhToD3h", Scopes: []string{"https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/userinfo.email"}, Endpoint: google.Endpoint, }, // Some random string, random for each request DefaultUserGroup: "default", ag: authAgent, syncDb: syncdb.NewSyncDB(), reg: register, } return &NewlyCreatedOauthHandler } //HandleOauthLogin xxx func (oh *OauthHandler) HandleLogin(w http.ResponseWriter, r *http.Request) { //add cookies redirect, e := r.URL.Query()["redirect"] uuid := "" if !e || len(redirect[0]) < 1 { uuid = oh.syncDb.Store("/") } else { uuid = oh.syncDb.Store(redirect[0]) } oh.addCookie(w, "uuid_login", uuid, 30*time.Minute) //handle redirect url := oh.googleOauthConfig.AuthCodeURL(uuid) http.Redirect(w, r, url, http.StatusTemporaryRedirect) } //OauthAuthorize xxx func (oh *OauthHandler) HandleAuthorize(w http.ResponseWriter, r *http.Request) { //read the uuid(aka the state parameter) uuid, err := r.Cookie("uuid_login") if err != nil { w.Header().Set("Content-Type", "text/html; charset=UTF-8") w.Write([]byte("Invalid redirect URI.")) } state := r.FormValue("state") if state != uuid.Value { w.Header().Set("Content-Type", "text/html; charset=UTF-8") w.Write([]byte("Invalid oauth state.")) return } code := r.FormValue("code") token, err := oh.googleOauthConfig.Exchange(oauth2.NoContext, code) if err != nil { w.Header().Set("Content-Type", "text/html; charset=UTF-8") w.Write([]byte("Code exchange failed.")) 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) if !oh.ag.UserExists(data.Email) { //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) } else { w.Header().Set("Content-Type", "text/html; charset=UTF-8") w.Write([]byte("You are not allowed to register in this system. Back")) } } else { log.Println(data.Email + " logged in via OAuth.") oh.ag.LoginUserByRequest(w, r, data.Email, true) //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) } } func (oh *OauthHandler) CheckOAuth(w http.ResponseWriter, r *http.Request) { sendJSONResponse(w, "true") } //https://golangcode.com/add-a-http-cookie/ func (oh *OauthHandler) addCookie(w http.ResponseWriter, name, value string, ttl time.Duration) { expire := time.Now().Add(ttl) cookie := http.Cookie{ Name: name, Value: value, Expires: expire, } http.SetCookie(w, &cookie) }