Unable to access login page in Golang - go

I am new to Golang. I have made a demo app for practice in which i have login register and homepage. When i go to login page it redirects to home page . I am not understanding what is happening.
This is my go code
package main
import (
"database/sql"
"fmt"
"net/http"
_ "github.com/go-sql-driver/mysql"
"golang.org/x/crypto/bcrypt"
)
var db *sql.DB
var err error
func signupPage(res http.ResponseWriter, req *http.Request) {
fmt.Println("entered Signup")
if req.Method != "POST" {
http.ServeFile(res, req, "template/signup.html")
return
}
email := req.FormValue("email")
password := req.FormValue("password")
var user string
err := db.QueryRow("SELECT email FROM users WHERE email=?", email).Scan(&user)
switch {
case err == sql.ErrNoRows:
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
http.Error(res, "Server error, unable to create your account.", 500)
return
}
_, err = db.Exec("INSERT INTO users(email, password) VALUES(?, ?)", email, hashedPassword)
if err != nil {
http.Error(res, "Server error, unable to create your account.", 500)
}
res.Write([]byte("User Registered Successfully"))
return
case err != nil:
http.Error(res, "Server error, unable to create your account.", 500)
return
default:
http.Redirect(res, req, "/", 301)
}
}
func loginPage(res http.ResponseWriter, req *http.Request) {
fmt.Println("Entered login")
if req.Method != "POST" {
http.ServeFile(res, req, "template/login.html")
return
}
email := req.FormValue("email")
password := req.FormValue("password")
var dbemail string
var dbpassword string
err := db.QueryRow("SELECT email, password FORM users WHERE email=?", email).Scan(&dbemail, &dbpassword)
if err != nil {
http.Redirect(res, req, "/login", 301)
return
}
err = bcrypt.CompareHashAndPassword([]byte(dbpassword), []byte(password))
if err != nil {
http.Redirect(res, req, "/login", 301)
return
}
res.Write([]byte("Hello" + dbemail))
}
func homePage(res http.ResponseWriter, req *http.Request) {
http.ServeFile(res, req, "template/landing.html")
}
func main() {
db, err = sql.Open("mysql", "root:password#/golang_demo")
if err != nil {
panic(err.Error())
} else {
fmt.Println("Database connected successfully")
}
defer db.Close()
err = db.Ping()
if err != nil {
panic(err.Error())
}
http.HandleFunc("/login", loginPage)
http.HandleFunc("/", homePage)
http.HandleFunc("/signup", signupPage)
http.ListenAndServe(":9090", nil)
}
When i go to signup page it goes successfully. But when i go to login page it is redirecting me to home page. Please help!

This is just an educated guess, since from the code I am seeing it doesn't look like that should happen. Since you are using 301 redirects (Moved Permanently), I would guess that at some point in writing your function and testing it, you did a redirect to the home page. Since it is "moved permanently", the browser now doesn't even ask the server if it should redirect when it sees that URL, it just does it.
If you're in chrome, open the dev tools, and disabling the cache should resolve it. Or even better, try it in a different browser that you haven't used on this site yet, and see if it works there.

Related

ERR_EMPTY_RESPONSE on refreshing page using google oauth2

I'm using google oauth services, provided by golang.org/x/oauth2 library. I can successfully login and get data as needed. Also, store token values in DB.
However, when logged in and I refresh the page, it results in an error,
This page isn’t working
localhost didn’t send any data.
ERR_EMPTY_RESPONSE
After getting some online references, I tried refresh_tokens, however, the error still persists.
Code for oauth2 client
const OauthGoogleUrlAPI = "https://www.googleapis.com/oauth2/v2/userinfo?access_token="
func OAuthClient(ctx context.Context, userId string) (client *http.Client, err error) {
var userToken *oauth2.Token
if userToken, err = GetToken(userId); err != nil {
if userToken, err = newToken(ctx, userId); err != nil {
return
}
}
if !userToken.Valid() { // if user token is expired
updatedToken, err := GoogleOauthConfig.TokenSource(context.TODO(), userToken).Token()
if err != nil {
log.Printf("\n\nError refreshing token ; Error : %s\n\n", err)
}
return GoogleOauthConfig.Client(ctx, updatedToken), err
}
return GoogleOauthConfig.Client(ctx, userToken), err
}
Here, GetToken retrieves existing tokens from db, newToken updates them in db.
The Callback Handler Code,
func GoogleCallBackHandler(w http.ResponseWriter, r *http.Request) {
var code string
temp = r.URL.Query()["code"]
for i := range temp {
code = temp[i]
}
token, err := GoogleOauthConfig.Exchange(context.Background(), code)
HandleError(err)
response, err := http.Get(OauthGoogleUrlAPI + token.AccessToken)
HandleError(err)
defer response.Body.Close()
user, err := ioutil.ReadAll(response.Body)
HandleError(err)
session, err := Store.Get(r, "authSession")
HandleError(err)
session.Values["user"] = string(user)
err = session.Save(r, w)
HandleError(err)
//Get user data in struct form
var userJson User
json.Unmarshal(user, &userJson)
//resp, err := client.Get("")
//database Store
err = InsertUserDetails(userJson, token.AccessToken, token.RefreshToken, token.Expiry)
HandleError(err)
w.Write([]byte("<html><head><title>Golang OAuth</title></head><body>" +
"Hi, " + string(user) + "<br>" +
"<a href='/logout'><button>Logout</button></a><br>" +
"</body></html>"))
client, err := UserOAuthClient(oauth2.NoContext, userJson.ID)
//resp, err := client.Get("")
}
the callback URL is of the form
http://localhost:3002/google/callback?state=state-token&code=4%2F0QGia33kbVbx2lsk92KFGEivY240zjnw9pnwmqJX_zZVCLbn_YASIMVcORIfK_ysNNYzCiBVzMc7qFJbjVjgfTM&scope=email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+openid&authuser=0&prompt=consent#
I'm confused about putting things together and about the flow. It'll be great if you could point out mistakes or make suggestions.
Thanks!

How to save a session in golang

I'm trying to save a logged user ID in my golang backend with gorilla sessions and securecookie.
Here is my package session :
package session
import (
"fmt"
"net/http"
"github.com/gorilla/securecookie"
"github.com/gorilla/sessions"
)
var store = sessions.NewCookieStore(securecookie.GenerateRandomKey(32))
//GetSessionLoggedID returns loggedID
func GetSessionLoggedID(r *http.Request) int {
storeAuth, _ := store.Get(r, "authentication")
if auth, ok := storeAuth.Values["loggedID"].(bool); ok && auth {
return storeAuth.Values["loggedID"].(int)
}
fmt.Println("none found")
return 0
}
//SetSessionLoggedID sets cookie session user ID
func SetSessionLoggedID(w http.ResponseWriter, r *http.Request, id int) {
storeAuth, err := store.Get(r, "authentication")
if err != nil {
fmt.Println(err.Error())
}
storeAuth.Options = &sessions.Options{HttpOnly: true, Secure: true, MaxAge: 2628000, Path: "/"}
storeAuth.Values["loggedID"] = id
storeAuth.Save(r, w)
}
I have another package that gets to verify email / password of a user that logs in.
Here is the function :
func (handler *UserHandler) checkPassword(w http.ResponseWriter, r *http.Request) {
var body struct {
Email string
Password string
}
err := json.NewDecoder(r.Body).Decode(&body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
loggedID, err := handler.UserUsecase.PasswordMatch(body.Email, body.Password)
if err != nil || loggedID == 0 {
http.Error(w, "Could not authenticate user", http.StatusUnauthorized)
return
}
session.SetSessionLoggedID(w, r, loggedID)
json.NewEncoder(w).Encode(struct {
ID int `json:"id"`
}{loggedID})
}
The ID returned is the proper one. But the session is not saving as I would have liked.
If I add a session.GetSessionLoggedID(r) at the end of checkpassword function, I get "none found".
What am I missing ?
// watch this line
if auth, ok := storeAuth.Values["loggedID"].(bool); ok && auth {
storeAuth.Values["loggedID"] is not bool, so ok is false, then you get "none found"
Change to
if auth, ok := storeAuth.Values["loggedID"]; ok{
return auth.(int)
}
fmt.Println("none found")

Using Colly framework I can't login to the Evernote account

I am using colly framework for scraping the website. Am trying to login the Evernote account for scraping some things. But I can't go through it. I used "username" and "password" titles for giving the credentials. Is this the right way ?.
Thank you in advance.
package main
import (
"log"
"github.com/gocolly/colly"
)
func main() {
// create a new collector
c := colly.NewCollector()
// authenticate
err := c.Post("https://www.evernote.com/Login.action",
map[string]string{"username":
"XXXXXX#XXX.com", "password": "*********"})
if err != nil {
log.Fatal("Error : ",err)
}
// attach callbacks after login
c.OnResponse(func(r *colly.Response) {
log.Println("response received", r.StatusCode)
})
// start scraping
c.Visit("https://www.evernote.com/")
}
You should try to mimic the browser behavior, take a look at this implementation, I've added comments on each step:
package evernote
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/http/cookiejar"
"net/url"
"regexp"
"strings"
)
const (
evernoteLoginURL = "https://www.evernote.com/Login.action"
)
var (
evernoteJSParamsExpr = regexp.MustCompile(`document.getElementById\("(.*)"\).value = "(.*)"`)
evernoteRedirectExpr = regexp.MustCompile(`Redirecting to <a href="(.*)">`)
errNoMatches = errors.New("No matches")
errRedirectURL = errors.New("Redirect URL not found")
)
// EvernoteClient wraps all methods required to interact with the website.
type EvernoteClient struct {
Username string
Password string
httpClient *http.Client
// These parameters persist during the login process:
hpts string
hptsh string
}
// NewEvernoteClient initializes a new Evernote client.
func NewEvernoteClient(username, password string) *EvernoteClient {
// Allocate a new cookie jar to mimic the browser behavior:
cookieJar, _ := cookiejar.New(nil)
// Fill up basic data:
c := &EvernoteClient{
Username: username,
Password: password,
}
// When initializing the http.Client, copy default values from http.DefaultClient
// Pass a pointer to the cookie jar that was created earlier:
c.httpClient = &http.Client{
Transport: http.DefaultTransport,
CheckRedirect: http.DefaultClient.CheckRedirect,
Jar: cookieJar,
Timeout: http.DefaultClient.Timeout,
}
return c
}
func (e *EvernoteClient) extractJSParams(body []byte) (err error) {
matches := evernoteJSParamsExpr.FindAllSubmatch(body, -1)
if len(matches) == 0 {
return errNoMatches
}
for _, submatches := range matches {
if len(submatches) < 3 {
err = errNoMatches
break
}
key := submatches[1]
val := submatches[2]
if bytes.Compare(key, hptsKey) == 0 {
e.hpts = string(val)
}
if bytes.Compare(key, hptshKey) == 0 {
e.hptsh = string(val)
}
}
return nil
}
// Login handles the login action.
func (e *EvernoteClient) Login() error {
// First step: fetch the login page as a browser visitor would do:
res, err := e.httpClient.Get(evernoteLoginURL)
if err != nil {
return err
}
if res.Body == nil {
return errors.New("No response body")
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
err = e.extractJSParams(body)
if err != nil {
return err
}
// Second step: we have extracted the "hpts" and "hptsh" parameters
// We send a request using only the username and setting "evaluateUsername":
values := &url.Values{}
values.Set("username", e.Username)
values.Set("evaluateUsername", "")
values.Set("analyticsLoginOrigin", "login_action")
values.Set("clipperFlow", "false")
values.Set("showSwitchService", "true")
values.Set("hpts", e.hpts)
values.Set("hptsh", e.hptsh)
rawValues := values.Encode()
req, err := http.NewRequest(http.MethodPost, evernoteLoginURL, bytes.NewBufferString(rawValues))
if err != nil {
return err
}
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
req.Header.Set("x-requested-with", "XMLHttpRequest")
req.Header.Set("referer", evernoteLoginURL)
res, err = e.httpClient.Do(req)
if err != nil {
return err
}
body, err = ioutil.ReadAll(res.Body)
if err != nil {
return err
}
bodyStr := string(body)
if !strings.Contains(bodyStr, `"usePasswordAuth":true`) {
return errors.New("Password auth not enabled")
}
// Third step: do the final request, append password to form data:
values.Del("evaluateUsername")
values.Set("password", e.Password)
values.Set("login", "Sign in")
rawValues = values.Encode()
req, err = http.NewRequest(http.MethodPost, evernoteLoginURL, bytes.NewBufferString(rawValues))
if err != nil {
return err
}
req.Header.Set("Accept", "text/html")
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
req.Header.Set("x-requested-with", "XMLHttpRequest")
req.Header.Set("referer", evernoteLoginURL)
res, err = e.httpClient.Do(req)
if err != nil {
return err
}
// Check the body in order to find the redirect URL:
body, err = ioutil.ReadAll(res.Body)
if err != nil {
return err
}
bodyStr = string(body)
matches := evernoteRedirectExpr.FindAllStringSubmatch(bodyStr, -1)
if len(matches) == 0 {
return errRedirectURL
}
m := matches[0]
if len(m) < 2 {
return errRedirectURL
}
redirectURL := m[1]
fmt.Println("Login is ok, redirect URL:", redirectURL)
return nil
}
After you successfully get the redirect URL, you should be able to send authenticated requests as long as you keep using the HTTP client that was used for the login process, the cookie jar plays a very important role here.
To call this code use:
func main() {
evernoteClient := NewEvernoteClient("user#company", "password")
err := evernoteClient.Login()
if err != nil {
panic(err)
}
}

Gorilla session.AddFlash Does Not Add Flash Message

I have a registration page with two handlers, one for displaying the form, one for processing a form submission.
I am trying to use a session.AddFlash method to save an error, then do 302 redirect back to the registration form and display the error.
I set up a session store:
package web
import (
"github.com/gorilla/sessions"
)
var sessionStore = sessions.NewCookieStore([]byte(sessionSecret))
Then my handlers look like this:
package web
import (
"html/template"
"log"
"net/http"
)
func registerForm(w http.ResponseWriter, r *http.Request) {
session, err := sessionStore.Get(r, "mysession")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
data := map[string]interface{}{}
log.Print("Flashes: ")
log.Print(session.Flashes())
if flashes := session.Flashes(); len(flashes) > 0 {
data["error"] = flashes[0]
}
tmpl, _ := template.ParseFiles("web/templates/register.html.tmpl")
tmpl.Execute(w, data)
}
func register(w http.ResponseWriter, r *http.Request) {
session, err := sessionStore.Get(r, "mysession")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
r.ParseForm()
username := r.Form["username"][0]
password := r.Form["password"][0]
if UserExists(username) {
log.Print("Username already taken")
session.AddFlash("Username already taken")
http.Redirect(w, r, "/web/register", http.StatusFound)
return
}
_, err = CreateUser(username, password)
log.Print(err)
if err != nil {
session.AddFlash(err.Error())
http.Redirect(w, r, "/web/register", http.StatusFound)
return
}
http.Redirect(w, r, "/web/login", http.StatusFound)
}
By adding logs I can see that UserExists returns true therefor a flash message should be added however after redirection to the form handler there is no flash message saved in the session.
I think you have to save the session before you redirect.
session.Save(r, w)
http://www.gorillatoolkit.org/pkg/sessions#Session.Save

golang session variables not working. what am i doing incorrectly?

I am using the gorilla/sessions package to implement sessions. the relevant code (or at least what I think is the only relevant part) is as follows:
// Function handler for executing HTML code
func lobbyHandler(w http.ResponseWriter, req *http.Request) {
if isLoggedIn := validateSession(w, req); isLoggedIn {
lobbyTempl.Execute(w, req.Host)
} else {
homeTempl.Execute(w, map[string]string{
"loginErrors": "Must log in first",
})
}
}
// Serves the files as needed, whenever they are requested
// used for all images, js, css, and other static files
func sourceHandler(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, r.URL.Path[1:])
}
func loginHandler(w http.ResponseWriter, r *http.Request) {
un, pw := r.FormValue("lUn"), r.FormValue("lPw")
if usr := findUser(un, pw); usr != nil {
if createSession(w, r) {
http.Redirect(w, req, "/lobby.html", http.StatusFound)
}
} else {
homeTempl.Execute(w, map[string]string{
"loginErrors": "User not found",
})
}
}
func createSession(w http.ResponseWriter, r *http.Request) bool {
session, _ := store.Get(r, sessionName)
session.Values["isAuthorized"] = true
if err := session.Save(r, w); err != nil {
fmt.Println("saving error: ", err.Error())
return false
}
return true
}
func validateSession(w http.ResponseWriter, r *http.Request) bool {
if session, err := store.Get(r, sessionName); err == nil {
if v, ok := session.Values["isAuthorized"]; ok && v == true {
fmt.Println("Authorized user identified!")
return true
} else {
fmt.Println("Unauthorized user detected!")
return false
}
}
return false
}
func main() {
//...
// serving files for the game
http.HandleFunc("/", homeHandler)
http.Handle("/ws", websocket.Handler(wsLobbyHandler))
http.HandleFunc("/lobby.html", lobbyHandler)
http.HandleFunc("/formlogin", loginHandler)
//...
//http.HandleFunc("/*.html", SourceHandler)
if err := http.ListenAndServeTLS(*addr, "cert.pem", "key.pem", nil); err != nil {
log.Fatal("ListenAndServe:", err)
}
}`
in my html i have:
<form id="login_form" action="/formlogin" method="post">
When logging in, the request is handled within loginHandler
The user is identified correctly from the database and a session is created (via createSession()) and placed into the cookie store.
But after the redirect to lobby.html, back in loginHandler
http.Redirect(w, req, "/lobby.html", http.StatusFound)
the validation within lobbyHandler does not work. Does this have to do with the store.Save(...) altering the headers?
I'm very new to go, as well as web apps in general, so I would really appreciate feedback.
Thanks to the comments, i was able to stumble across a similar search that works for me.
session.Options = &sessions.Options{
Path: "/lobby.html",
}
I needed to make sure the cookies know where they are going to be redirected properly.

Resources