mirror of
https://github.com/1f349/tulip.git
synced 2024-12-23 00:34:07 +00:00
Redesign token authentication
This commit is contained in:
parent
807c5c540c
commit
3555742316
@ -1,8 +1,7 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/1f349/mjwt"
|
"errors"
|
||||||
"github.com/1f349/mjwt/auth"
|
|
||||||
"github.com/1f349/tulip/database"
|
"github.com/1f349/tulip/database"
|
||||||
"github.com/1f349/tulip/database/types"
|
"github.com/1f349/tulip/database/types"
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
@ -14,7 +13,7 @@ import (
|
|||||||
type UserHandler func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, auth UserAuth)
|
type UserHandler func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, auth UserAuth)
|
||||||
|
|
||||||
type UserAuth struct {
|
type UserAuth struct {
|
||||||
ID string
|
Subject string
|
||||||
NeedOtp bool
|
NeedOtp bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,14 +25,16 @@ func (u UserAuth) NextFlowUrl(origin *url.URL) *url.URL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u UserAuth) IsGuest() bool {
|
func (u UserAuth) IsGuest() bool {
|
||||||
return u.ID == ""
|
return u.Subject == ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrAuthHttpError = errors.New("auth http error")
|
||||||
|
|
||||||
func (h *HttpServer) RequireAdminAuthentication(next UserHandler) httprouter.Handle {
|
func (h *HttpServer) RequireAdminAuthentication(next UserHandler) httprouter.Handle {
|
||||||
return h.RequireAuthentication(func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, auth UserAuth) {
|
return h.RequireAuthentication(func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, auth UserAuth) {
|
||||||
var role types.UserRole
|
var role types.UserRole
|
||||||
if h.DbTx(rw, func(tx *database.Queries) (err error) {
|
if h.DbTx(rw, func(tx *database.Queries) (err error) {
|
||||||
role, err = tx.GetUserRole(req.Context(), auth.ID)
|
role, err = tx.GetUserRole(req.Context(), auth.Subject)
|
||||||
return
|
return
|
||||||
}) {
|
}) {
|
||||||
return
|
return
|
||||||
@ -59,28 +60,38 @@ func (h *HttpServer) RequireAuthentication(next UserHandler) httprouter.Handle {
|
|||||||
|
|
||||||
func (h *HttpServer) OptionalAuthentication(flowPart bool, next UserHandler) httprouter.Handle {
|
func (h *HttpServer) OptionalAuthentication(flowPart bool, next UserHandler) httprouter.Handle {
|
||||||
return func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) {
|
return func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) {
|
||||||
authData, err := h.internalAuthenticationHandler(req)
|
authData, err := h.internalAuthenticationHandler(rw, req)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
|
if !errors.Is(err, ErrAuthHttpError) {
|
||||||
|
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
if n := authData.NextFlowUrl(req.URL); n != nil && !flowPart {
|
if n := authData.NextFlowUrl(req.URL); n != nil && !flowPart {
|
||||||
http.Redirect(rw, req, n.String(), http.StatusFound)
|
http.Redirect(rw, req, n.String(), http.StatusFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
next(rw, req, params, authData)
|
next(rw, req, params, authData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpServer) internalAuthenticationHandler(req *http.Request) (UserAuth, error) {
|
func (h *HttpServer) internalAuthenticationHandler(rw http.ResponseWriter, req *http.Request) (UserAuth, error) {
|
||||||
if loginCookie, err := req.Cookie("tulip-login-data"); err == nil {
|
http.SetCookie(rw, &http.Cookie{
|
||||||
_, b, err := mjwt.ExtractClaims[auth.AccessTokenClaims](h.signingKey, loginCookie.Value)
|
Name: "tulip-login-data",
|
||||||
|
Path: "/",
|
||||||
|
MaxAge: -1,
|
||||||
|
Secure: true,
|
||||||
|
SameSite: http.SameSiteLaxMode,
|
||||||
|
})
|
||||||
|
|
||||||
|
var u UserAuth
|
||||||
|
err := h.readLoginAccessCookie(rw, req, &u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return UserAuth{}, err
|
|
||||||
}
|
|
||||||
return UserAuth{ID: b.Subject, NeedOtp: b.Claims.Perms.Has("needs-otp")}, nil
|
|
||||||
}
|
|
||||||
// not logged in
|
// not logged in
|
||||||
return UserAuth{}, nil
|
return UserAuth{}, nil
|
||||||
}
|
}
|
||||||
|
return u, nil
|
||||||
|
}
|
||||||
|
|
||||||
func PrepareRedirectUrl(targetPath string, origin *url.URL) *url.URL {
|
func PrepareRedirectUrl(targetPath string, origin *url.URL) *url.URL {
|
||||||
// find start of query parameters in target path
|
// find start of query parameters in target path
|
||||||
|
@ -21,7 +21,7 @@ func TestUserAuth_NextFlowUrl(t *testing.T) {
|
|||||||
func TestUserAuth_IsGuest(t *testing.T) {
|
func TestUserAuth_IsGuest(t *testing.T) {
|
||||||
var u UserAuth
|
var u UserAuth
|
||||||
assert.True(t, u.IsGuest())
|
assert.True(t, u.IsGuest())
|
||||||
u.ID = uuid.NewString()
|
u.Subject = uuid.NewString()
|
||||||
assert.False(t, u.IsGuest())
|
assert.False(t, u.IsGuest())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,10 +47,10 @@ func TestOptionalAuthentication(t *testing.T) {
|
|||||||
h := &HttpServer{}
|
h := &HttpServer{}
|
||||||
req, err := http.NewRequest(http.MethodGet, "https://example.com/hello", nil)
|
req, err := http.NewRequest(http.MethodGet, "https://example.com/hello", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
auth, err := h.internalAuthenticationHandler(req)
|
auth, err := h.internalAuthenticationHandler(nil, req)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, auth.IsGuest())
|
assert.True(t, auth.IsGuest())
|
||||||
auth.ID = "567"
|
auth.Subject = "567"
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPrepareRedirectUrl(t *testing.T) {
|
func TestPrepareRedirectUrl(t *testing.T) {
|
||||||
|
21
server/db.go
21
server/db.go
@ -1,22 +1,33 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"github.com/1f349/tulip/database"
|
"github.com/1f349/tulip/database"
|
||||||
"github.com/1f349/tulip/logger"
|
"github.com/1f349/tulip/logger"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ErrDatabaseActionFailed = errors.New("database action failed")
|
||||||
|
|
||||||
// DbTx wraps a database transaction with http error messages and a simple action
|
// DbTx wraps a database transaction with http error messages and a simple action
|
||||||
// function. If the action function returns an error the transaction will be
|
// function. If the action function returns an error the transaction will be
|
||||||
// rolled back. If there is no error then the transaction is committed.
|
// rolled back. If there is no error then the transaction is committed.
|
||||||
func (h *HttpServer) DbTx(rw http.ResponseWriter, action func(db *database.Queries) error) bool {
|
func (h *HttpServer) DbTx(rw http.ResponseWriter, action func(tx *database.Queries) error) bool {
|
||||||
err := action(h.db)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(rw, "Database error", http.StatusInternalServerError)
|
|
||||||
logger.Logger.Helper()
|
logger.Logger.Helper()
|
||||||
logger.Logger.Warn("Database action error", "err", err)
|
if h.DbTxError(action) != nil {
|
||||||
|
http.Error(rw, "Database error", http.StatusInternalServerError)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *HttpServer) DbTxError(action func(tx *database.Queries) error) error {
|
||||||
|
logger.Logger.Helper()
|
||||||
|
err := action(h.db)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.Warn("Database action error", "err", err)
|
||||||
|
return ErrDatabaseActionFailed
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -16,7 +16,7 @@ func (h *HttpServer) EditGet(rw http.ResponseWriter, req *http.Request, _ httpro
|
|||||||
|
|
||||||
if h.DbTx(rw, func(tx *database.Queries) error {
|
if h.DbTx(rw, func(tx *database.Queries) error {
|
||||||
var err error
|
var err error
|
||||||
user, err = tx.GetUser(req.Context(), auth.ID)
|
user, err = tx.GetUser(req.Context(), auth.Subject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read user data: %w", err)
|
return fmt.Errorf("failed to read user data: %w", err)
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ func (h *HttpServer) EditPost(rw http.ResponseWriter, req *http.Request, _ httpr
|
|||||||
Zoneinfo: patch.ZoneInfo,
|
Zoneinfo: patch.ZoneInfo,
|
||||||
Locale: patch.Locale,
|
Locale: patch.Locale,
|
||||||
UpdatedAt: time.Now(),
|
UpdatedAt: time.Now(),
|
||||||
Subject: auth.ID,
|
Subject: auth.Subject,
|
||||||
}
|
}
|
||||||
if h.DbTx(rw, func(tx *database.Queries) error {
|
if h.DbTx(rw, func(tx *database.Queries) error {
|
||||||
if err := tx.ModifyUser(req.Context(), m); err != nil {
|
if err := tx.ModifyUser(req.Context(), m); err != nil {
|
||||||
|
@ -34,15 +34,15 @@ func (h *HttpServer) Home(rw http.ResponseWriter, req *http.Request, _ httproute
|
|||||||
var userRole types.UserRole
|
var userRole types.UserRole
|
||||||
var hasTwoFactor bool
|
var hasTwoFactor bool
|
||||||
if h.DbTx(rw, func(tx *database.Queries) (err error) {
|
if h.DbTx(rw, func(tx *database.Queries) (err error) {
|
||||||
userWithName, err = tx.GetUserDisplayName(req.Context(), auth.ID)
|
userWithName, err = tx.GetUserDisplayName(req.Context(), auth.Subject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get user display name: %w", err)
|
return fmt.Errorf("failed to get user display name: %w", err)
|
||||||
}
|
}
|
||||||
hasTwoFactor, err = tx.HasOtp(req.Context(), auth.ID)
|
hasTwoFactor, err = tx.HasOtp(req.Context(), auth.Subject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get user two factor state: %w", err)
|
return fmt.Errorf("failed to get user two factor state: %w", err)
|
||||||
}
|
}
|
||||||
userRole, err = tx.GetUserRole(req.Context(), auth.ID)
|
userRole, err = tx.GetUserRole(req.Context(), auth.Subject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get user role: %w", err)
|
return fmt.Errorf("failed to get user role: %w", err)
|
||||||
}
|
}
|
||||||
@ -53,7 +53,7 @@ func (h *HttpServer) Home(rw http.ResponseWriter, req *http.Request, _ httproute
|
|||||||
pages.RenderPageTemplate(rw, "index", map[string]any{
|
pages.RenderPageTemplate(rw, "index", map[string]any{
|
||||||
"ServiceName": h.conf.ServiceName,
|
"ServiceName": h.conf.ServiceName,
|
||||||
"Auth": auth,
|
"Auth": auth,
|
||||||
"User": database.User{Subject: auth.ID, Name: userWithName, Role: userRole},
|
"User": database.User{Subject: auth.Subject, Name: userWithName, Role: userRole},
|
||||||
"Nonce": lNonce,
|
"Nonce": lNonce,
|
||||||
"OtpEnabled": hasTwoFactor,
|
"OtpEnabled": hasTwoFactor,
|
||||||
"IsAdmin": userRole == types.RoleAdmin,
|
"IsAdmin": userRole == types.RoleAdmin,
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/1f349/mjwt"
|
||||||
"github.com/1f349/mjwt/auth"
|
"github.com/1f349/mjwt/auth"
|
||||||
"github.com/1f349/mjwt/claims"
|
"github.com/1f349/mjwt/claims"
|
||||||
"github.com/1f349/tulip/database"
|
"github.com/1f349/tulip/database"
|
||||||
@ -35,8 +36,8 @@ func getUserLoginName(req *http.Request) string {
|
|||||||
return originUrl.Query().Get("login_name")
|
return originUrl.Query().Get("login_name")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpServer) LoginGet(rw http.ResponseWriter, req *http.Request, _ httprouter.Params, auth UserAuth) {
|
func (h *HttpServer) LoginGet(rw http.ResponseWriter, req *http.Request, _ httprouter.Params, userAuth UserAuth) {
|
||||||
if !auth.IsGuest() {
|
if !userAuth.IsGuest() {
|
||||||
h.SafeRedirect(rw, req)
|
h.SafeRedirect(rw, req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -53,7 +54,7 @@ func (h *HttpServer) LoginGet(rw http.ResponseWriter, req *http.Request, _ httpr
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpServer) LoginPost(rw http.ResponseWriter, req *http.Request, _ httprouter.Params, auth UserAuth) {
|
func (h *HttpServer) LoginPost(rw http.ResponseWriter, req *http.Request, _ httprouter.Params, userAuth UserAuth) {
|
||||||
un := req.FormValue("username")
|
un := req.FormValue("username")
|
||||||
pw := req.FormValue("password")
|
pw := req.FormValue("password")
|
||||||
|
|
||||||
@ -121,12 +122,13 @@ func (h *HttpServer) LoginPost(rw http.ResponseWriter, req *http.Request, _ http
|
|||||||
}
|
}
|
||||||
|
|
||||||
// only continues if the above tx succeeds
|
// only continues if the above tx succeeds
|
||||||
auth = UserAuth{
|
userAuth = UserAuth{
|
||||||
ID: userInfo.Subject,
|
Subject: userInfo.Subject,
|
||||||
NeedOtp: hasOtp,
|
NeedOtp: hasOtp,
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.setLoginDataCookie(rw, auth) {
|
if h.setLoginDataCookie(rw, userAuth) {
|
||||||
|
http.Error(rw, "Failed to save login cookie", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,29 +146,87 @@ func (h *HttpServer) LoginPost(rw http.ResponseWriter, req *http.Request, _ http
|
|||||||
h.SafeRedirect(rw, req)
|
h.SafeRedirect(rw, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
const oneYear = 365 * 24 * time.Hour
|
const twelveHours = 12 * time.Hour
|
||||||
|
const oneMonth = 30 * 24 * time.Hour
|
||||||
|
|
||||||
func (h *HttpServer) setLoginDataCookie(rw http.ResponseWriter, authData UserAuth) bool {
|
func (h *HttpServer) setLoginDataCookie(rw http.ResponseWriter, authData UserAuth) bool {
|
||||||
ps := claims.NewPermStorage()
|
ps := claims.NewPermStorage()
|
||||||
if authData.NeedOtp {
|
if authData.NeedOtp {
|
||||||
ps.Set("needs-otp")
|
ps.Set("needs-otp")
|
||||||
}
|
}
|
||||||
gen, err := h.signingKey.GenerateJwt(authData.ID, uuid.NewString(), jwt.ClaimStrings{h.conf.BaseUrl}, oneYear, auth.AccessTokenClaims{Perms: ps})
|
accId := uuid.NewString()
|
||||||
|
gen, err := h.signingKey.GenerateJwt(authData.Subject, accId, jwt.ClaimStrings{h.conf.BaseUrl}, twelveHours, auth.AccessTokenClaims{Perms: ps})
|
||||||
|
if err != nil {
|
||||||
|
http.Error(rw, "Failed to generate cookie token", http.StatusInternalServerError)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
ref, err := h.signingKey.GenerateJwt(authData.Subject, uuid.NewString(), jwt.ClaimStrings{h.conf.BaseUrl}, oneMonth, auth.RefreshTokenClaims{AccessTokenId: accId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(rw, "Failed to generate cookie token", http.StatusInternalServerError)
|
http.Error(rw, "Failed to generate cookie token", http.StatusInternalServerError)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
http.SetCookie(rw, &http.Cookie{
|
http.SetCookie(rw, &http.Cookie{
|
||||||
Name: "tulip-login-data",
|
Name: "tulip-login-access",
|
||||||
Value: gen,
|
Value: gen,
|
||||||
Path: "/",
|
Path: "/",
|
||||||
Expires: time.Now().AddDate(1, 0, 0),
|
|
||||||
Secure: true,
|
Secure: true,
|
||||||
|
HttpOnly: true,
|
||||||
|
SameSite: http.SameSiteLaxMode,
|
||||||
|
})
|
||||||
|
http.SetCookie(rw, &http.Cookie{
|
||||||
|
Name: "tulip-login-refresh",
|
||||||
|
Value: ref,
|
||||||
|
Path: "/",
|
||||||
|
Expires: time.Now().AddDate(0, 0, 32),
|
||||||
|
Secure: true,
|
||||||
|
HttpOnly: true,
|
||||||
SameSite: http.SameSiteLaxMode,
|
SameSite: http.SameSiteLaxMode,
|
||||||
})
|
})
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readJwtCookie[T mjwt.Claims](req *http.Request, cookieName string, signingKey mjwt.Verifier) (mjwt.BaseTypeClaims[T], error) {
|
||||||
|
loginCookie, err := req.Cookie(cookieName)
|
||||||
|
if err != nil {
|
||||||
|
return mjwt.BaseTypeClaims[T]{}, err
|
||||||
|
}
|
||||||
|
_, b, err := mjwt.ExtractClaims[T](signingKey, loginCookie.Value)
|
||||||
|
if err != nil {
|
||||||
|
return mjwt.BaseTypeClaims[T]{}, err
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpServer) readLoginAccessCookie(rw http.ResponseWriter, req *http.Request, u *UserAuth) error {
|
||||||
|
loginData, err := readJwtCookie[auth.AccessTokenClaims](req, "tulip-login-access", h.signingKey)
|
||||||
|
if err != nil {
|
||||||
|
return h.readLoginRefreshCookie(rw, req, u)
|
||||||
|
}
|
||||||
|
*u = UserAuth{
|
||||||
|
Subject: loginData.Subject,
|
||||||
|
NeedOtp: loginData.Claims.Perms.Has("needs-otp"),
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpServer) readLoginRefreshCookie(rw http.ResponseWriter, req *http.Request, userAuth *UserAuth) error {
|
||||||
|
refreshData, err := readJwtCookie[auth.RefreshTokenClaims](req, "tulip-login-refresh", h.signingKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*userAuth = UserAuth{
|
||||||
|
Subject: refreshData.Subject,
|
||||||
|
NeedOtp: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.setLoginDataCookie(rw, *userAuth) {
|
||||||
|
http.Error(rw, "Failed to save login cookie", http.StatusInternalServerError)
|
||||||
|
return fmt.Errorf("failed to save login cookie: %w", ErrAuthHttpError)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (h *HttpServer) LoginResetPasswordPost(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) {
|
func (h *HttpServer) LoginResetPasswordPost(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) {
|
||||||
email := req.PostFormValue("email")
|
email := req.PostFormValue("email")
|
||||||
address, err := mail.ParseAddress(email)
|
address, err := mail.ParseAddress(email)
|
||||||
|
@ -27,12 +27,12 @@ func (h *HttpServer) ManageAppsGet(rw http.ResponseWriter, req *http.Request, _
|
|||||||
var role types.UserRole
|
var role types.UserRole
|
||||||
var appList []database.GetAppListRow
|
var appList []database.GetAppListRow
|
||||||
if h.DbTx(rw, func(tx *database.Queries) (err error) {
|
if h.DbTx(rw, func(tx *database.Queries) (err error) {
|
||||||
role, err = tx.GetUserRole(req.Context(), auth.ID)
|
role, err = tx.GetUserRole(req.Context(), auth.Subject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
appList, err = tx.GetAppList(req.Context(), database.GetAppListParams{
|
appList, err = tx.GetAppList(req.Context(), database.GetAppListParams{
|
||||||
Owner: auth.ID,
|
Owner: auth.Subject,
|
||||||
Column2: role == types.RoleAdmin,
|
Column2: role == types.RoleAdmin,
|
||||||
Offset: int64(offset),
|
Offset: int64(offset),
|
||||||
})
|
})
|
||||||
@ -84,7 +84,7 @@ func (h *HttpServer) ManageAppsPost(rw http.ResponseWriter, req *http.Request, _
|
|||||||
if sso {
|
if sso {
|
||||||
var role types.UserRole
|
var role types.UserRole
|
||||||
if h.DbTx(rw, func(tx *database.Queries) (err error) {
|
if h.DbTx(rw, func(tx *database.Queries) (err error) {
|
||||||
role, err = tx.GetUserRole(req.Context(), auth.ID)
|
role, err = tx.GetUserRole(req.Context(), auth.Subject)
|
||||||
return
|
return
|
||||||
}) {
|
}) {
|
||||||
return
|
return
|
||||||
@ -107,7 +107,7 @@ func (h *HttpServer) ManageAppsPost(rw http.ResponseWriter, req *http.Request, _
|
|||||||
Name: name,
|
Name: name,
|
||||||
Secret: secret,
|
Secret: secret,
|
||||||
Domain: domain,
|
Domain: domain,
|
||||||
Owner: auth.ID,
|
Owner: auth.Subject,
|
||||||
Public: public,
|
Public: public,
|
||||||
Sso: sso,
|
Sso: sso,
|
||||||
Active: active,
|
Active: active,
|
||||||
@ -124,7 +124,7 @@ func (h *HttpServer) ManageAppsPost(rw http.ResponseWriter, req *http.Request, _
|
|||||||
Sso: sso,
|
Sso: sso,
|
||||||
Active: active,
|
Active: active,
|
||||||
Subject: req.FormValue("subject"),
|
Subject: req.FormValue("subject"),
|
||||||
Owner: auth.ID,
|
Owner: auth.Subject,
|
||||||
})
|
})
|
||||||
}) {
|
}) {
|
||||||
return
|
return
|
||||||
@ -145,7 +145,7 @@ func (h *HttpServer) ManageAppsPost(rw http.ResponseWriter, req *http.Request, _
|
|||||||
err = tx.ResetClientAppSecret(req.Context(), database.ResetClientAppSecretParams{
|
err = tx.ResetClientAppSecret(req.Context(), database.ResetClientAppSecretParams{
|
||||||
Secret: secret,
|
Secret: secret,
|
||||||
Subject: sub,
|
Subject: sub,
|
||||||
Owner: auth.ID,
|
Owner: auth.Subject,
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
}) {
|
}) {
|
||||||
|
@ -31,7 +31,7 @@ func (h *HttpServer) ManageUsersGet(rw http.ResponseWriter, req *http.Request, _
|
|||||||
var role types.UserRole
|
var role types.UserRole
|
||||||
var userList []database.GetUserListRow
|
var userList []database.GetUserListRow
|
||||||
if h.DbTx(rw, func(tx *database.Queries) (err error) {
|
if h.DbTx(rw, func(tx *database.Queries) (err error) {
|
||||||
role, err = tx.GetUserRole(req.Context(), auth.ID)
|
role, err = tx.GetUserRole(req.Context(), auth.Subject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ func (h *HttpServer) ManageUsersGet(rw http.ResponseWriter, req *http.Request, _
|
|||||||
"Users": userList,
|
"Users": userList,
|
||||||
"Offset": offset,
|
"Offset": offset,
|
||||||
"EmailShow": req.URL.Query().Has("show-email"),
|
"EmailShow": req.URL.Query().Has("show-email"),
|
||||||
"CurrentAdmin": auth.ID,
|
"CurrentAdmin": auth.Subject,
|
||||||
"Namespace": h.conf.Namespace,
|
"Namespace": h.conf.Namespace,
|
||||||
}
|
}
|
||||||
if q.Has("edit") {
|
if q.Has("edit") {
|
||||||
@ -80,7 +80,7 @@ func (h *HttpServer) ManageUsersPost(rw http.ResponseWriter, req *http.Request,
|
|||||||
|
|
||||||
var role types.UserRole
|
var role types.UserRole
|
||||||
if h.DbTx(rw, func(tx *database.Queries) (err error) {
|
if h.DbTx(rw, func(tx *database.Queries) (err error) {
|
||||||
role, err = tx.GetUserRole(req.Context(), auth.ID)
|
role, err = tx.GetUserRole(req.Context(), auth.Subject)
|
||||||
return
|
return
|
||||||
}) {
|
}) {
|
||||||
return
|
return
|
||||||
|
@ -80,11 +80,11 @@ func (h *HttpServer) authorizeEndpoint(rw http.ResponseWriter, req *http.Request
|
|||||||
var user string
|
var user string
|
||||||
var hasOtp bool
|
var hasOtp bool
|
||||||
if h.DbTx(rw, func(tx *database.Queries) (err error) {
|
if h.DbTx(rw, func(tx *database.Queries) (err error) {
|
||||||
user, err = tx.GetUserDisplayName(req.Context(), auth.ID)
|
user, err = tx.GetUserDisplayName(req.Context(), auth.Subject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hasOtp, err = tx.HasOtp(req.Context(), auth.ID)
|
hasOtp, err = tx.HasOtp(req.Context(), auth.Subject)
|
||||||
return
|
return
|
||||||
}) {
|
}) {
|
||||||
return
|
return
|
||||||
@ -117,7 +117,7 @@ func (h *HttpServer) authorizeEndpoint(rw http.ResponseWriter, req *http.Request
|
|||||||
|
|
||||||
if !isSSO {
|
if !isSSO {
|
||||||
otpInput := req.FormValue("code")
|
otpInput := req.FormValue("code")
|
||||||
if h.fetchAndValidateOtp(rw, auth.ID, otpInput) {
|
if h.fetchAndValidateOtp(rw, auth.Subject, otpInput) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,7 +147,7 @@ func (h *HttpServer) oauthUserAuthorization(rw http.ResponseWriter, req *http.Re
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
auth, err := h.internalAuthenticationHandler(req)
|
auth, err := h.internalAuthenticationHandler(rw, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -169,5 +169,5 @@ func (h *HttpServer) oauthUserAuthorization(rw http.ResponseWriter, req *http.Re
|
|||||||
http.Redirect(rw, req, redirectUrl.String(), http.StatusFound)
|
http.Redirect(rw, req, redirectUrl.String(), http.StatusFound)
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
return auth.ID, nil
|
return auth.Subject, nil
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ func (h *HttpServer) LoginOtpPost(rw http.ResponseWriter, req *http.Request, _ h
|
|||||||
}
|
}
|
||||||
|
|
||||||
otpInput := req.FormValue("code")
|
otpInput := req.FormValue("code")
|
||||||
if h.fetchAndValidateOtp(rw, auth.ID, otpInput) {
|
if h.fetchAndValidateOtp(rw, auth.Subject, otpInput) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,13 +86,13 @@ func (h *HttpServer) EditOtpPost(rw http.ResponseWriter, req *http.Request, _ ht
|
|||||||
}
|
}
|
||||||
|
|
||||||
otpInput := req.Form.Get("code")
|
otpInput := req.Form.Get("code")
|
||||||
if h.fetchAndValidateOtp(rw, auth.ID, otpInput) {
|
if h.fetchAndValidateOtp(rw, auth.Subject, otpInput) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.DbTx(rw, func(tx *database.Queries) error {
|
if h.DbTx(rw, func(tx *database.Queries) error {
|
||||||
return tx.SetOtp(req.Context(), database.SetOtpParams{
|
return tx.SetOtp(req.Context(), database.SetOtpParams{
|
||||||
Subject: auth.ID,
|
Subject: auth.Subject,
|
||||||
Secret: "",
|
Secret: "",
|
||||||
Digits: 0,
|
Digits: 0,
|
||||||
})
|
})
|
||||||
@ -128,7 +128,7 @@ func (h *HttpServer) EditOtpPost(rw http.ResponseWriter, req *http.Request, _ ht
|
|||||||
var email string
|
var email string
|
||||||
if h.DbTx(rw, func(tx *database.Queries) error {
|
if h.DbTx(rw, func(tx *database.Queries) error {
|
||||||
var err error
|
var err error
|
||||||
email, err = tx.GetUserEmail(req.Context(), auth.ID)
|
email, err = tx.GetUserEmail(req.Context(), auth.Subject)
|
||||||
return err
|
return err
|
||||||
}) {
|
}) {
|
||||||
return
|
return
|
||||||
@ -177,7 +177,7 @@ func (h *HttpServer) EditOtpPost(rw http.ResponseWriter, req *http.Request, _ ht
|
|||||||
|
|
||||||
if h.DbTx(rw, func(tx *database.Queries) error {
|
if h.DbTx(rw, func(tx *database.Queries) error {
|
||||||
return tx.SetOtp(req.Context(), database.SetOtpParams{
|
return tx.SetOtp(req.Context(), database.SetOtpParams{
|
||||||
Subject: auth.ID,
|
Subject: auth.Subject,
|
||||||
Secret: secret,
|
Secret: secret,
|
||||||
Digits: int64(digits),
|
Digits: int64(digits),
|
||||||
})
|
})
|
||||||
|
@ -124,7 +124,14 @@ func NewHttpServer(conf Conf, db *database.Queries, signingKey mjwt.Signer) *htt
|
|||||||
}
|
}
|
||||||
if subtle.ConstantTimeCompare([]byte(cookie.Value), []byte(req.PostFormValue("nonce"))) == 1 {
|
if subtle.ConstantTimeCompare([]byte(cookie.Value), []byte(req.PostFormValue("nonce"))) == 1 {
|
||||||
http.SetCookie(rw, &http.Cookie{
|
http.SetCookie(rw, &http.Cookie{
|
||||||
Name: "tulip-login-data",
|
Name: "tulip-login-access",
|
||||||
|
Path: "/",
|
||||||
|
MaxAge: -1,
|
||||||
|
Secure: true,
|
||||||
|
SameSite: http.SameSiteLaxMode,
|
||||||
|
})
|
||||||
|
http.SetCookie(rw, &http.Cookie{
|
||||||
|
Name: "tulip-login-refresh",
|
||||||
Path: "/",
|
Path: "/",
|
||||||
MaxAge: -1,
|
MaxAge: -1,
|
||||||
Secure: true,
|
Secure: true,
|
||||||
|
Loading…
Reference in New Issue
Block a user