Skip to content
user_authentication.go 6.59 KiB
Newer Older
Simon Pastor's avatar
Simon Pastor committed
/*
 * Copyright (c) 2020  InterDigital Communications, Inc
 *
 * Licensed under the Apache License, Version 2.0 (the \"License\");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an \"AS IS\" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * AdvantEDGE Platform Controller REST API
 *
 * This API is the main Platform Controller API for scenario configuration & sandbox management <p>**Micro-service**<br>[meep-pfm-ctrl](https://github.com/InterDigitalInc/AdvantEDGE/tree/master/go-apps/meep-platform-ctrl) <p>**Type & Usage**<br>Platform main interface used by controller software to configure scenarios and manage sandboxes in the AdvantEDGE platform <p>**Details**<br>API details available at _your-AdvantEDGE-ip-address/api_
 *
 * API version: 1.0.0
 * Contact: AdvantEDGE@InterDigital.com
 * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
 */

package server

import (
	"encoding/json"
	"net/http"

	log "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-logger"
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"github.com/rs/xid"
)

// User holds a users account information
type User struct {
	Username  string
	Password  string
	SessionId string
	Active    bool
}

var user1 = User{"u1", "1234", "NA", false}
var user2 = User{"u2", "2345", "NA", false}
var user3 = User{"u3", "3456", "NA", false}

// Map of configured users - Key=Username
var ConfiguredUsers map[string]*User

// Map of connected users - key=SessionId
var ConnectedUsers map[string]*User

// store will hold all session data
var CookieStore *sessions.CookieStore

func init() {
	log.Info("Initializing User Auth.")

	//CookieStore = sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY")))
	//CookieStore = sessions.NewCookieStore([]byte("veryprivatekey"))

	// The code below is problematic because keys are lost when the app is restarted
	// This causes existing cookies on the client side to become undecipherable and causes user to have to login
	// A strategy to persist these keys should be imagined
	authKeyOne := securecookie.GenerateRandomKey(64)
	encryptionKeyOne := securecookie.GenerateRandomKey(32)
	CookieStore = sessions.NewCookieStore(
		authKeyOne,
		encryptionKeyOne,
	)

	CookieStore.Options = &sessions.Options{
		MaxAge:   60 * 15,
		HttpOnly: true,
	}
	// uncomment when ready to test with HTTPS
	//Secure: true
	// Not sure SameSite is supported by Gorilla Sessions
	//SameSite --

	// add preconfigured users
	ConfiguredUsers = make(map[string]*User)
	ConfiguredUsers[user1.Username] = &user1
	ConfiguredUsers[user2.Username] = &user2
	ConfiguredUsers[user3.Username] = &user3

	// no active sessions
	ConnectedUsers = make(map[string]*User)

	//PrintUsers()

}

func uaLoginUser(w http.ResponseWriter, r *http.Request) {
	log.Info("----- LOGIN -----")
	//PrintConnectedUsers()
	// Get session cookie
	session, err := CookieStore.Get(r, "authCookie")
	if err != nil {
		log.Info(err.Error())
		// Cookie decryption may fail on microservice restart due to
		// mismatch with newly created cookie store encryption keys (no persistence).
		// In this case use the newly generated session, if successfully created.
		if session == nil {
Simon Pastor's avatar
Simon Pastor committed
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
	//PrintSession(session)

	// Get form data
	username := r.FormValue("username")
	password := r.FormValue("password")

	// Authenticate user
	// Does user exist?
	user, ok := ConfiguredUsers[username]
	if !ok {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}
	// Does user have an existing session
	if user.Active {
		DeactivateUser(user)
	}
	// Does password match?
	if user.Password != password {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}

	// user exists & password match - Let's get it done
	user.Active = true
	user.SessionId = xid.New().String()
	ConnectedUsers[user.SessionId] = user
	session.Values["SessionId"] = user.SessionId
	err = session.Save(r, w)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	//PrintSession(session)
	//PrintConnectedUsers()
}

func uaLogoutUser(w http.ResponseWriter, r *http.Request) {
	log.Info("----- LOGOUT -----")
	//PrintConnectedUsers()
	// Get session cookie
	session, err := CookieStore.Get(r, "authCookie")
	if err != nil {
		http.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}
	//PrintSession(session)

	sid, _ := session.Values["SessionId"].(string)
	user, ok := ConnectedUsers[sid]
	if !ok {
		http.Error(w, "Invalid session id", http.StatusUnauthorized)
		return

	}

	DeactivateUser(user)
	// Invalidate session
	session.Values["SessionId"] = ""
	session.Options.MaxAge = -1
	err = session.Save(r, w)
	if err != nil {
		http.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	//PrintSession(session)
	//PrintConnectedUsers()
}

func IsActiveSession(r *http.Request) bool {

	log.Info("----- IS ACTIVE -----")
	// Get session cookie
	session, err := CookieStore.Get(r, "authCookie")
	if err != nil {
		log.Info("Invalid session")
		return false
	}
	//PrintSession(session)

	sid, _ := session.Values["SessionId"].(string)
	user, ok := ConnectedUsers[sid]
	if !ok {
		log.Info("Invalid sid")
		return false
	}

	if user.Active {
		log.Info("OK")
		return true
	}
	//PrintUser("Invalid", user)
	return false
}

func DeactivateUser(user *User) {
	log.Info("Deactivate")
	// DB management
	_, ok := ConnectedUsers[user.SessionId]
	if ok {
		delete(ConnectedUsers, user.SessionId)
	}
	user.Active = false
	user.SessionId = "NA"
}

func PrintSession(session *sessions.Session) {
	//str,_ := json.Marshal(session.Values)
	str, ok := session.Values["SessionId"].(string)
	if !ok {
		str = "nil"
	}
	log.Info("Session: " + str)
}

func PrintUser(msg string, user *User) {
	str, _ := json.Marshal(*user)
	log.Info(msg + " " + string(str))
}

func PrintUsers() {
	str, _ := json.Marshal(ConfiguredUsers)
	log.Info("ConfiguredUsers:" + string(str))
	str, _ = json.Marshal(ConnectedUsers)
	log.Info("ConnectedUsers:" + string(str))
}

func PrintConnectedUsers() {
	str, _ := json.Marshal(ConnectedUsers)
	log.Info("ConnectedUsers:" + string(str))
}