WIP
This commit is contained in:
parent
4b93d7dace
commit
effa79aacd
10 changed files with 56 additions and 20 deletions
4
API.md
4
API.md
|
|
@ -17,7 +17,7 @@ Typically each request takes only a second to execute.
|
||||||
NOTE: These routes will be documented using a Swagger / OpenAPI definition in the future.
|
NOTE: These routes will be documented using a Swagger / OpenAPI definition in the future.
|
||||||
All routes can be found under `/api/v1/http/`
|
All routes can be found under `/api/v1/http/`
|
||||||
|
|
||||||
- `/api/v1/auth`: Returns user information
|
- `/api/v1/auth`: Returns api session information
|
||||||
- `/api/v1/systems`: Returns a (publically visible) list of systems
|
- `/api/v1/systems`: Returns a (publically visible) list of systems
|
||||||
- `/api/v1/news`: Returns JSON containing all news items
|
- `/api/v1/news`: Returns JSON containing all news items
|
||||||
|
|
||||||
|
|
@ -54,4 +54,4 @@ Each input is sent directly to the underlying process.
|
||||||
|
|
||||||
### Supported Websocket Calls
|
### Supported Websocket Calls
|
||||||
|
|
||||||
(to be documented)
|
(to be documented)
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ func (a *API) HandleRoute(ctx context.Context, path string) (http.Handler, error
|
||||||
|
|
||||||
Handler: func(s string, r *http.Request) (ai AuthInfo, err error) {
|
Handler: func(s string, r *http.Request) (ai AuthInfo, err error) {
|
||||||
var user *auth.AuthUser
|
var user *auth.AuthUser
|
||||||
user, ai.Token, err = a.Dependencies.Auth.UserOf(r)
|
user, err = a.Dependencies.Auth.SessionOf(r)
|
||||||
if user != nil {
|
if user != nil {
|
||||||
ai.User = user.User.User
|
ai.User = user.User.User
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ func (next *Next) HandleRoute(ctx context.Context, path string) (http.Handler, e
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the user
|
// get the user
|
||||||
user, _, err := next.Dependencies.Auth.UserOf(r)
|
user, _, err := next.Dependencies.Auth.SessionOf(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, err
|
return "", 0, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ func (auth *Auth) Protect(handler http.Handler, AllowToken bool, scope component
|
||||||
|
|
||||||
// load the user in the session
|
// load the user in the session
|
||||||
// TODO<tokens>: Check if API access is allowed
|
// TODO<tokens>: Check if API access is allowed
|
||||||
user, token, err := auth.UserOf(r)
|
user, token, err := auth.SessionOf(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
goto err
|
goto err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,6 @@ func (*AdminLoggedIn) Scope() component.ScopeInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (al *AdminLoggedIn) HasScope(param string, r *http.Request) (bool, error) {
|
func (al *AdminLoggedIn) HasScope(param string, r *http.Request) (bool, error) {
|
||||||
user, _, err := al.Dependencies.Auth.UserOf(r)
|
user, _, err := al.Dependencies.Auth.SessionOf(r)
|
||||||
return user != nil && user.IsAdmin() && user.IsTOTPEnabled(), err
|
return user != nil && user.IsAdmin() && user.IsTOTPEnabled(), err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,6 @@ func (*UserLoggedIn) Scope() component.ScopeInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iu *UserLoggedIn) HasScope(param string, r *http.Request) (bool, error) {
|
func (iu *UserLoggedIn) HasScope(param string, r *http.Request) (bool, error) {
|
||||||
user, _, err := iu.Dependencies.Auth.UserOf(r)
|
user, _, err := iu.Dependencies.Auth.SessionOf(r)
|
||||||
return user != nil, err
|
return user != nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,27 +18,30 @@ import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UserOf returns the user logged into the provided request.
|
// SessionOf returns the session and user logged into the provided request.
|
||||||
// token indicates if the user used a token to authenticate, or a browser session was used.
|
// token indicates if the user used a token to authenticate, or a browser session was used.
|
||||||
// A token takes priority over a user in a session.
|
// A token takes priority over a user in a session.
|
||||||
//
|
//
|
||||||
// If there is no user associated with the given request, user and error are nil, and token is false.
|
// If there is no user associated with the given request, user and error are nil, and token is false.
|
||||||
// An invalid session, expired token, or disabled user all result in user = nil.
|
// An invalid session, expired token, or disabled user all result in user = nil.
|
||||||
//
|
//
|
||||||
// When no UserOf exists in the given session returns nil.
|
// When no SessionOf exists in the given session returns nil.
|
||||||
func (auth *Auth) UserOf(r *http.Request) (user *AuthUser, token bool, err error) {
|
func (auth *Auth) SessionOf(r *http.Request) (session component.SessionInfo, user *AuthUser, err error) {
|
||||||
// check the user from the token first
|
// check the user from the token first
|
||||||
{
|
{
|
||||||
user, err := auth.UserOfToken(r)
|
user, err := auth.UserOfToken(r)
|
||||||
if user != nil && err == nil {
|
if user != nil && err == nil {
|
||||||
return user, true, nil
|
return component.SessionInfo{User: &user.User, Token: true}, user, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback to using session
|
// fallback to using session
|
||||||
{
|
{
|
||||||
user, err := auth.UserOfSession(r)
|
user, err := auth.UserOfSession(r)
|
||||||
return user, false, err
|
if err != nil {
|
||||||
|
return component.SessionInfo{}, nil, err
|
||||||
|
}
|
||||||
|
return component.SessionInfo{User: &user.User, Token: false}, user, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
package component
|
package component
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Scope represents a single permit by a session to perform some action.
|
// Scope represents a single permit by a session to perform some action.
|
||||||
|
|
@ -58,6 +61,36 @@ type ScopeProvider interface {
|
||||||
// Scopes returns information about the scope
|
// Scopes returns information about the scope
|
||||||
Scope() ScopeInfo
|
Scope() ScopeInfo
|
||||||
|
|
||||||
// Check checks if the given session has access to the given scope
|
// Check checks if the given session has access to the given scope.
|
||||||
HasScope(param string, r *http.Request) (bool, error)
|
HasScope(param string, r *http.Request) (bool, error)
|
||||||
|
// TODO: move this to a session
|
||||||
|
}
|
||||||
|
|
||||||
|
// SessionInfo provides information about the current session.
|
||||||
|
type SessionInfo struct {
|
||||||
|
// User is the current user associated with the session.
|
||||||
|
User *models.User
|
||||||
|
|
||||||
|
// Token indicates if the user was authenticated with a Token
|
||||||
|
Token bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (si SessionInfo) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(struct {
|
||||||
|
User string `json:"user"`
|
||||||
|
Token bool `json:"token"`
|
||||||
|
}{User: si.Username(), Token: si.Token})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Username reports the username associated with this session
|
||||||
|
func (si SessionInfo) Username() string {
|
||||||
|
if si.User == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return si.User.User
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anonymous reports if this Session is associated with a user account
|
||||||
|
func (si SessionInfo) Anonymous() bool {
|
||||||
|
return si.Username() != ""
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ func (li *ListInstances) ShouldShowList(r *http.Request) bool {
|
||||||
return allowPrivate
|
return allowPrivate
|
||||||
}
|
}
|
||||||
|
|
||||||
user, _, _ := li.Dependencies.Auth.UserOf(r)
|
user, _, _ := li.Dependencies.Auth.SessionOf(r)
|
||||||
if user == nil {
|
if user == nil {
|
||||||
return allowPublic
|
return allowPublic
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,14 @@ const UserTable = "users"
|
||||||
type User struct {
|
type User struct {
|
||||||
Pk uint `gorm:"column:pk;primaryKey"`
|
Pk uint `gorm:"column:pk;primaryKey"`
|
||||||
|
|
||||||
User string `gorm:"column:user;not null;unique"` // name of the user
|
User string `gorm:"column:user;not null;unique"` // name of the user
|
||||||
PasswordHash []byte `gorm:"column:password"` // password of the user, hashed
|
|
||||||
|
|
||||||
TOTPEnabled *bool `gorm:"column:totpenabled"` // is totp enabled for the user
|
PasswordHash []byte `gorm:"column:password" json:"-"` // password of the user, hashed
|
||||||
TOTPURL string `gorm:"column:totp"` // the totp of the user
|
TOTPEnabled *bool `gorm:"column:totpenabled" json:"-"` // is totp enabled for the user
|
||||||
|
TOTPURL string `gorm:"column:totp" json:"-"` // the totp of the user
|
||||||
|
|
||||||
Enabled *bool `gorm:"enabled;not null"`
|
Enabled *bool `gorm:"enabled;not null" json:"enabled"`
|
||||||
Admin *bool `gorm:"column:admin;not null"`
|
Admin *bool `gorm:"column:admin;not null" json:"admin"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (user *User) HasPassword() bool {
|
func (user *User) HasPassword() bool {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue