2024-01-04 20:19:47 +01:00
|
|
|
package webservice
|
|
|
|
|
|
|
|
import (
|
|
|
|
// External
|
|
|
|
"github.com/google/uuid"
|
|
|
|
|
|
|
|
// Internal
|
|
|
|
"git.gibonuddevalla.se/go/webservice/session"
|
|
|
|
|
|
|
|
// Standard
|
|
|
|
"encoding/json"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type AuthenticationRequest struct {
|
2024-01-30 07:06:42 +01:00
|
|
|
UserID int `json:"-"`
|
|
|
|
Username string
|
|
|
|
Password string
|
|
|
|
Additional interface{}
|
2024-01-04 20:19:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
type AuthenticationResponse struct {
|
2024-01-30 07:06:42 +01:00
|
|
|
OK bool
|
2024-01-04 20:19:47 +01:00
|
|
|
Authenticated bool
|
2024-01-30 07:06:42 +01:00
|
|
|
UserID int
|
2024-02-14 14:34:36 +01:00
|
|
|
MFA any
|
2024-01-04 20:19:47 +01:00
|
|
|
}
|
|
|
|
|
2024-02-14 14:34:36 +01:00
|
|
|
type AuthenticationHandler func(AuthenticationRequest, *session.T, bool) (AuthenticationResponse, error)
|
2024-01-04 20:19:47 +01:00
|
|
|
type AuthorizationHandler func(*session.T, *http.Request) (bool, error)
|
|
|
|
|
2024-01-06 10:15:01 +01:00
|
|
|
func (service *Service) sessionNew(w http.ResponseWriter, r *http.Request, foo *session.T) { // {{{
|
|
|
|
var sess session.T
|
2024-01-04 20:19:47 +01:00
|
|
|
var found bool
|
|
|
|
var err error
|
|
|
|
|
|
|
|
for {
|
2024-01-06 10:15:01 +01:00
|
|
|
sess.UUID = uuid.NewString()
|
2024-01-04 20:19:47 +01:00
|
|
|
if service.Db == nil {
|
2024-01-06 10:15:01 +01:00
|
|
|
if _, found = service.sessions[sess.UUID]; found {
|
2024-01-04 20:19:47 +01:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2024-01-06 10:15:01 +01:00
|
|
|
sess.Authenticated = false
|
|
|
|
sess.Created = time.Now()
|
|
|
|
service.sessions[sess.UUID] = &sess
|
2024-01-04 20:19:47 +01:00
|
|
|
break
|
|
|
|
|
|
|
|
} else {
|
2024-02-14 14:34:36 +01:00
|
|
|
if _, found = service.RetrieveSession(sess.UUID); found {
|
2024-01-04 20:19:47 +01:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2024-01-06 10:15:01 +01:00
|
|
|
err = service.Db.NewSession(sess.UUID)
|
2024-01-04 20:19:47 +01:00
|
|
|
if err != nil {
|
2024-01-06 10:15:01 +01:00
|
|
|
service.errorHandler(err, "001-A001", w)
|
2024-01-04 20:19:47 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2024-01-06 10:15:01 +01:00
|
|
|
service.logger.Info("session", "op", "new", "uuid", sess.UUID)
|
2024-01-05 09:00:09 +01:00
|
|
|
|
2024-01-04 20:19:47 +01:00
|
|
|
respJSON, _ := json.Marshal(
|
|
|
|
struct {
|
2024-01-30 07:06:42 +01:00
|
|
|
OK bool
|
2024-01-06 10:15:01 +01:00
|
|
|
Session session.T
|
2024-01-04 20:19:47 +01:00
|
|
|
}{
|
|
|
|
true,
|
2024-01-06 10:15:01 +01:00
|
|
|
sess,
|
2024-01-04 20:19:47 +01:00
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
w.Write(respJSON)
|
|
|
|
} // }}}
|
|
|
|
func (service *Service) sessionAuthenticate(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
|
2024-01-30 07:06:42 +01:00
|
|
|
var authenticatedByFramework bool
|
2024-01-04 20:19:47 +01:00
|
|
|
var authResponse AuthenticationResponse
|
|
|
|
var err error
|
|
|
|
reqBody, _ := io.ReadAll(r.Body)
|
|
|
|
|
|
|
|
// Username and password are provided in this JSON authentication request.
|
|
|
|
var authRequest AuthenticationRequest
|
|
|
|
err = json.Unmarshal(reqBody, &authRequest)
|
|
|
|
if err != nil {
|
2024-01-06 10:15:01 +01:00
|
|
|
service.errorHandler(err, "001-0004", w)
|
2024-01-04 20:19:47 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Authenticate against webservice user table if using a database.
|
2024-02-14 14:34:36 +01:00
|
|
|
var userID int = sess.UserID
|
|
|
|
if service.Db != nil && userID == 0 {
|
2024-01-30 07:06:42 +01:00
|
|
|
authenticatedByFramework, userID, err = service.Db.Authenticate(authRequest.Username, authRequest.Password)
|
2024-01-04 20:19:47 +01:00
|
|
|
if err != nil {
|
2024-01-06 10:15:01 +01:00
|
|
|
service.errorHandler(err, "001-A002", w)
|
2024-01-04 20:19:47 +01:00
|
|
|
return
|
|
|
|
}
|
2024-01-30 07:06:42 +01:00
|
|
|
authRequest.UserID = userID
|
2024-01-04 20:19:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// The authentication handler is provided with the authenticated response of the possible database authentication,
|
|
|
|
// and given a chance to override it.
|
2024-02-14 14:34:36 +01:00
|
|
|
authResponse, err = service.authenticationHandler(authRequest, sess, authenticatedByFramework)
|
2024-01-04 20:19:47 +01:00
|
|
|
if err != nil {
|
2024-01-06 10:15:01 +01:00
|
|
|
service.errorHandler(err, "001-F002", w)
|
2024-01-04 20:19:47 +01:00
|
|
|
return
|
|
|
|
}
|
2024-02-14 14:34:36 +01:00
|
|
|
|
2024-01-05 22:24:04 +01:00
|
|
|
authResponse.UserID = userID
|
|
|
|
authResponse.OK = true
|
2024-01-04 20:19:47 +01:00
|
|
|
sess.Authenticated = authResponse.Authenticated
|
|
|
|
|
2024-02-14 14:34:36 +01:00
|
|
|
if authResponse.MFA != nil {
|
|
|
|
err = service.Db.SetSessionMFA(sess.UUID, authResponse.MFA)
|
|
|
|
if err != nil {
|
|
|
|
service.errorHandler(err, "001-A003", w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-30 07:06:42 +01:00
|
|
|
if authResponse.Authenticated && userID > 0 {
|
|
|
|
err = service.Db.SetSessionUser(sess.UUID, userID)
|
|
|
|
if err != nil {
|
|
|
|
service.errorHandler(err, "001-A003", w)
|
|
|
|
return
|
|
|
|
}
|
2024-02-03 10:53:12 +01:00
|
|
|
service.Db.UpdateUserTime(userID)
|
2024-01-30 07:06:42 +01:00
|
|
|
}
|
|
|
|
|
2024-01-04 20:19:47 +01:00
|
|
|
authResp, _ := json.Marshal(authResponse)
|
|
|
|
w.Write(authResp)
|
|
|
|
} // }}}
|
2024-01-30 07:06:42 +01:00
|
|
|
func (service *Service) sessionRetrieve(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
|
2024-01-05 19:59:18 +01:00
|
|
|
response := struct {
|
2024-01-30 07:06:42 +01:00
|
|
|
OK bool
|
2024-01-05 19:59:18 +01:00
|
|
|
Session *session.T
|
|
|
|
}{
|
|
|
|
true,
|
|
|
|
sess,
|
|
|
|
}
|
|
|
|
out, _ := json.Marshal(response)
|
|
|
|
w.Write(out)
|
2024-01-30 07:06:42 +01:00
|
|
|
} // }}}
|
2024-01-05 19:59:18 +01:00
|
|
|
|
2024-02-14 14:34:36 +01:00
|
|
|
func (service *Service) RetrieveSession(uuid string) (session *session.T, found bool) { // {{{
|
2024-01-04 20:19:47 +01:00
|
|
|
var err error
|
|
|
|
|
|
|
|
if service.Db == nil {
|
|
|
|
session, found = service.sessions[uuid]
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
session, err = service.Db.RetrieveSession(uuid)
|
|
|
|
if err != nil {
|
|
|
|
service.logger.Error("session", "error", err)
|
|
|
|
session = nil
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
found = (session != nil)
|
|
|
|
return
|
|
|
|
} // }}}
|