/operations/version1/SessionOperationsV1.go
package operations1
import (
"context"
"encoding/json"
"net/http"
"sync"
"time"
accclients1 "github.com/pip-services-users/pip-clients-accounts-go/version1"
passclients1 "github.com/pip-services-users/pip-clients-passwords-go/version1"
roleclients1 "github.com/pip-services-users/pip-clients-roles-go/version1"
sessclients1 "github.com/pip-services-users/pip-clients-sessions-go/version1"
cdata "github.com/pip-services4/pip-services4-go/pip-services4-commons-go/data"
cerr "github.com/pip-services4/pip-services4-go/pip-services4-commons-go/errors"
cconf "github.com/pip-services4/pip-services4-go/pip-services4-components-go/config"
cref "github.com/pip-services4/pip-services4-go/pip-services4-components-go/refer"
httpcontroller "github.com/pip-services4/pip-services4-go/pip-services4-http-go/controllers"
)
type SessionsOperationsV1 struct {
*httpcontroller.RestOperations
defaultConfig *cconf.ConfigParams
cookie string
cookieEnabled bool
maxCookieAge int64
accountsClient accclients1.IAccountsClientV1
sessionsClient sessclients1.ISessionsClientV1
passwordsClient passclients1.IPasswordsClientV1
rolesClient roleclients1.IRolesClientV1
}
func NewSessionsOperationsV1(ctx context.Context) *SessionsOperationsV1 {
c := SessionsOperationsV1{
RestOperations: httpcontroller.NewRestOperations(),
}
c.defaultConfig = cconf.NewConfigParamsFromTuples(
"options.cookie_enabled", true,
"options.cookie", "x-session-id",
"options.max_cookie_age", 365*24*60*60*1000,
)
c.cookie = "x-session-id"
c.cookieEnabled = true
c.maxCookieAge = 365 * 24 * 60 * 60 * 1000
c.DependencyResolver.Put(ctx, "accounts", cref.NewDescriptor("pip-services-accounts", "client", "*", "*", "1.0"))
c.DependencyResolver.Put(ctx, "passwords", cref.NewDescriptor("pip-services-passwords", "client", "*", "*", "1.0"))
c.DependencyResolver.Put(ctx, "roles", cref.NewDescriptor("pip-services-roles", "client", "*", "*", "1.0"))
c.DependencyResolver.Put(ctx, "sessions", cref.NewDescriptor("pip-services-sessions", "client", "*", "*", "1.0"))
return &c
}
func (c *SessionsOperationsV1) Configure(ctx context.Context, config *cconf.ConfigParams) {
config = config.SetDefaults(c.defaultConfig)
c.DependencyResolver.Configure(ctx, config)
c.cookieEnabled = config.GetAsBooleanWithDefault("options.cookie_enabled", c.cookieEnabled)
c.cookie = config.GetAsStringWithDefault("options.cookie", c.cookie)
c.maxCookieAge = config.GetAsLongWithDefault("options.max_cookie_age", c.maxCookieAge)
}
func (c *SessionsOperationsV1) SetReferences(ctx context.Context, references cref.IReferences) {
c.RestOperations.SetReferences(ctx, references)
dependency, _ := c.DependencyResolver.GetOneRequired("sessions")
sesionsClient, ok1 := dependency.(sessclients1.ISessionsClientV1)
if !ok1 {
panic("SessionOperationsV1: Cant't resolv dependency 'client' to ISessionsClientV1")
}
c.sessionsClient = sesionsClient
dependency, _ = c.DependencyResolver.GetOneRequired("accounts")
acountClient, ok2 := dependency.(accclients1.IAccountsClientV1)
if !ok2 {
panic("SessionOperationsV1: Cant't resolv dependency 'client' to IAccountsClientV1")
}
c.accountsClient = acountClient
dependency, _ = c.DependencyResolver.GetOneRequired("passwords")
passClient, ok3 := dependency.(passclients1.IPasswordsClientV1)
if !ok3 {
panic("SessionOperationsV1: Cant't resolv dependency 'client' to IPasswordsClientV1")
}
c.passwordsClient = passClient
dependency, _ = c.DependencyResolver.GetOneRequired("roles")
rolesClient, ok4 := dependency.(roleclients1.IRolesClientV1)
if !ok4 {
panic("SessionOperationsV1: Cant't resolv dependency 'client' to IRolesClientV1")
}
c.rolesClient = rolesClient
}
func (c *SessionsOperationsV1) LoadSession(res http.ResponseWriter, req *http.Request, next http.HandlerFunc) {
sessionId := req.Header.Get("x-session-id")
if sessionId != "" {
session, err := c.sessionsClient.GetSessionById("facade", sessionId)
if session == nil && err == nil {
err = cerr.NewUnauthorizedError(
"facade",
"SESSION_NOT_FOUND",
"Session invalid or already expired.",
).WithDetails("session_id", sessionId).WithStatus(440)
}
if err == nil {
// Associate session user with the request
buf, _ := json.Marshal(session.User)
user := make(map[string]interface{}, 0)
json.Unmarshal(buf, &user)
req = req.WithContext(context.WithValue(req.Context(), "user_id", session.UserId))
req = req.WithContext(context.WithValue(req.Context(), "user_name", session.UserName))
req = req.WithContext(context.WithValue(req.Context(), "user", *cdata.NewAnyValueMapFromValue(user)))
req = req.WithContext(context.WithValue(req.Context(), "session_id", session.Id))
next.ServeHTTP(res, req)
} else {
c.SendError(res, req, err)
}
} else {
next.ServeHTTP(res, req)
}
}
func (c *SessionsOperationsV1) OpenSession(res http.ResponseWriter, req *http.Request, account *accclients1.AccountV1, roles []string) {
var session *sessclients1.SessionV1
var settings cconf.ConfigParams
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
passwordInfo, err := c.passwordsClient.GetPasswordInfo("", account.Id)
if err != nil {
c.SendError(res, req, err)
return
}
var changePwdTime time.Time
if passwordInfo != nil {
changePwdTime = passwordInfo.ChangeTime
}
var user = SessionUserV1{
Id: account.Id,
Name: account.Name,
Login: account.Login,
CreateTime: account.CreateTime,
TimeZone: account.TimeZone,
Language: account.Language,
Theme: account.Theme,
Roles: roles,
Settings: settings,
ChangePwdTime: changePwdTime,
CustomHdr: account.CustomHdr,
CustomDat: account.CustomDat,
}
address := httpcontroller.HttpRequestDetector.DetectAddress(req)
client := httpcontroller.HttpRequestDetector.DetectBrowser(req)
session, err = c.sessionsClient.OpenSession("", account.Id, account.Name, address, client, user, nil)
if err != nil {
c.SendError(res, req, err)
return
}
//res.json(session)
c.SendResult(res, req, session, nil)
}()
wg.Wait()
}
func (c *SessionsOperationsV1) Signup(res http.ResponseWriter, req *http.Request) {
signupData := make(map[string]interface{})
c.DecodeBody(req, &signupData)
r, ok := signupData["roles"].([]string)
roles := make([]string, 0)
if ok {
roles = append(roles, r...)
}
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
// Use email by default
login, ok := signupData["login"].(string)
if !ok {
login, _ = signupData["email"].(string)
}
// Create account
newAccount := accclients1.AccountV1{}
newAccount.Name, _ = signupData["name"].(string)
newAccount.Login = login
newAccount.Language, _ = signupData["language"].(string)
newAccount.Theme, _ = signupData["theme"].(string)
newAccount.TimeZone, _ = signupData["time_zone"].(string)
account, err := c.accountsClient.CreateAccount("", &newAccount)
if err != nil {
c.SendError(res, req, err)
return
}
// Create password for the account
password, _ := signupData["password"].(string)
err = c.passwordsClient.SetPassword(
"", account.Id, password)
if err != nil {
c.SendError(res, req, err)
return
}
// Create roles for the account
if len(roles) > 0 {
c.rolesClient.GrantRoles(
"", account.Id, roles)
}
c.OpenSession(res, req, account, roles)
}()
wg.Wait()
}
func (c *SessionsOperationsV1) Signin(res http.ResponseWriter, req *http.Request) {
login := c.GetParam(req, "login")
password := c.GetParam(req, "password")
if login == "" && password == "" {
params := make(map[string]string, 0)
c.DecodeBody(req, ¶ms)
login = params["login"]
password = params["password"]
}
roles := make([]string, 0)
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
// Find user account
account, err := c.accountsClient.GetAccountByIdOrLogin("", login)
if err != nil {
c.SendError(res, req, err)
return
}
if err == nil && account == nil {
err = cerr.NewBadRequestError(
"",
"WRONG_LOGIN",
"Account "+login+" was not found",
).WithDetails("login", login)
if err != nil {
c.SendError(res, req, err)
return
}
}
// Authenticate user
result, err := c.passwordsClient.Authenticate("", account.Id, password)
// wrong password error is UNKNOWN when use http client
if (err == nil && result == false) || (err != nil && err.(*cerr.ApplicationError).Cause == "Invalid password") {
err = cerr.NewBadRequestError(
"",
"WRONG_PASSWORD",
"Wrong password for account "+login,
).WithDetails("login", login)
if err != nil {
c.SendError(res, req, err)
return
}
}
// Retrieve user roles
if c.rolesClient != nil {
roles, err = c.rolesClient.GetRolesById("", account.Id)
if err != nil {
c.SendError(res, req, err)
return
}
} else {
roles = make([]string, 0)
}
c.OpenSession(res, req, account, roles)
}()
wg.Wait()
}
func (c *SessionsOperationsV1) Signout(res http.ResponseWriter, req *http.Request) {
sessionId, ok := req.Context().Value("session_id").(string)
if ok {
_, err := c.sessionsClient.CloseSession("", sessionId)
if err != nil {
c.SendError(res, req, err)
} else {
// res.json(204);
c.SendEmptyResult(res, req, nil)
}
} else {
//res.json(204);
c.SendEmptyResult(res, req, nil)
}
}