mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2024-12-26 13:29:05 +01:00
rename api userconfig to frontend, return json on api auth error
This commit is contained in:
parent
9d4767539c
commit
3afe40083d
@ -374,7 +374,7 @@ func main() {
|
|||||||
securedapi := r.PathPrefix("/api").Subrouter()
|
securedapi := r.PathPrefix("/api").Subrouter()
|
||||||
userapi := r.PathPrefix("/userapi").Subrouter()
|
userapi := r.PathPrefix("/userapi").Subrouter()
|
||||||
configapi := r.PathPrefix("/config").Subrouter()
|
configapi := r.PathPrefix("/config").Subrouter()
|
||||||
userconfigapi := r.PathPrefix("/userconfig").Subrouter()
|
frontendapi := r.PathPrefix("/frontend").Subrouter()
|
||||||
|
|
||||||
if !config.Keys.DisableAuthentication {
|
if !config.Keys.DisableAuthentication {
|
||||||
r.Handle("/login", authentication.Login(
|
r.Handle("/login", authentication.Login(
|
||||||
@ -447,15 +447,13 @@ func main() {
|
|||||||
// On success;
|
// On success;
|
||||||
next,
|
next,
|
||||||
|
|
||||||
// On failure:
|
// On failure: JSON Response
|
||||||
func(rw http.ResponseWriter, r *http.Request, err error) {
|
func(rw http.ResponseWriter, r *http.Request, err error) {
|
||||||
|
rw.Header().Add("Content-Type", "application/json")
|
||||||
rw.WriteHeader(http.StatusUnauthorized)
|
rw.WriteHeader(http.StatusUnauthorized)
|
||||||
web.RenderTemplate(rw, "login.tmpl", &web.Page{
|
json.NewEncoder(rw).Encode(map[string]string{
|
||||||
Title: "Authentication failed - ClusterCockpit",
|
"status": http.StatusText(http.StatusUnauthorized),
|
||||||
MsgType: "alert-danger",
|
"error": err.Error(),
|
||||||
Message: err.Error(),
|
|
||||||
Build: buildInfo,
|
|
||||||
Infos: info,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -465,15 +463,13 @@ func main() {
|
|||||||
// On success;
|
// On success;
|
||||||
next,
|
next,
|
||||||
|
|
||||||
// On failure:
|
// On failure: JSON Response
|
||||||
func(rw http.ResponseWriter, r *http.Request, err error) {
|
func(rw http.ResponseWriter, r *http.Request, err error) {
|
||||||
|
rw.Header().Add("Content-Type", "application/json")
|
||||||
rw.WriteHeader(http.StatusUnauthorized)
|
rw.WriteHeader(http.StatusUnauthorized)
|
||||||
web.RenderTemplate(rw, "login.tmpl", &web.Page{
|
json.NewEncoder(rw).Encode(map[string]string{
|
||||||
Title: "Authentication failed - ClusterCockpit",
|
"status": http.StatusText(http.StatusUnauthorized),
|
||||||
MsgType: "alert-danger",
|
"error": err.Error(),
|
||||||
Message: err.Error(),
|
|
||||||
Build: buildInfo,
|
|
||||||
Infos: info,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -483,33 +479,29 @@ func main() {
|
|||||||
// On success;
|
// On success;
|
||||||
next,
|
next,
|
||||||
|
|
||||||
// On failure:
|
// On failure: JSON Response
|
||||||
func(rw http.ResponseWriter, r *http.Request, err error) {
|
func(rw http.ResponseWriter, r *http.Request, err error) {
|
||||||
|
rw.Header().Add("Content-Type", "application/json")
|
||||||
rw.WriteHeader(http.StatusUnauthorized)
|
rw.WriteHeader(http.StatusUnauthorized)
|
||||||
web.RenderTemplate(rw, "login.tmpl", &web.Page{
|
json.NewEncoder(rw).Encode(map[string]string{
|
||||||
Title: "Authentication failed - ClusterCockpit",
|
"status": http.StatusText(http.StatusUnauthorized),
|
||||||
MsgType: "alert-danger",
|
"error": err.Error(),
|
||||||
Message: err.Error(),
|
|
||||||
Build: buildInfo,
|
|
||||||
Infos: info,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
userconfigapi.Use(func(next http.Handler) http.Handler {
|
frontendapi.Use(func(next http.Handler) http.Handler {
|
||||||
return authentication.AuthUserConfigApi(
|
return authentication.AuthFrontendApi(
|
||||||
// On success;
|
// On success;
|
||||||
next,
|
next,
|
||||||
|
|
||||||
// On failure:
|
// On failure: JSON Response
|
||||||
func(rw http.ResponseWriter, r *http.Request, err error) {
|
func(rw http.ResponseWriter, r *http.Request, err error) {
|
||||||
|
rw.Header().Add("Content-Type", "application/json")
|
||||||
rw.WriteHeader(http.StatusUnauthorized)
|
rw.WriteHeader(http.StatusUnauthorized)
|
||||||
web.RenderTemplate(rw, "login.tmpl", &web.Page{
|
json.NewEncoder(rw).Encode(map[string]string{
|
||||||
Title: "Authentication failed - ClusterCockpit",
|
"status": http.StatusText(http.StatusUnauthorized),
|
||||||
MsgType: "alert-danger",
|
"error": err.Error(),
|
||||||
Message: err.Error(),
|
|
||||||
Build: buildInfo,
|
|
||||||
Infos: info,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -532,7 +524,7 @@ func main() {
|
|||||||
api.MountApiRoutes(securedapi)
|
api.MountApiRoutes(securedapi)
|
||||||
api.MountUserApiRoutes(userapi)
|
api.MountUserApiRoutes(userapi)
|
||||||
api.MountConfigApiRoutes(configapi)
|
api.MountConfigApiRoutes(configapi)
|
||||||
api.MountUserConfigApiRoutes(userconfigapi)
|
api.MountFrontendApiRoutes(frontendapi)
|
||||||
|
|
||||||
if config.Keys.EmbedStaticFiles {
|
if config.Keys.EmbedStaticFiles {
|
||||||
if i, err := os.Stat("./var/img"); err == nil {
|
if i, err := os.Stat("./var/img"); err == nil {
|
||||||
|
@ -106,12 +106,13 @@ func (api *RestApi) MountConfigApiRoutes(r *mux.Router) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *RestApi) MountUserConfigApiRoutes(r *mux.Router) {
|
func (api *RestApi) MountFrontendApiRoutes(r *mux.Router) {
|
||||||
r.StrictSlash(true)
|
r.StrictSlash(true)
|
||||||
|
|
||||||
if api.Authentication != nil {
|
if api.Authentication != nil {
|
||||||
r.HandleFunc("/jwt/", api.getJWT).Methods(http.MethodGet) // Role:Admin Check in
|
r.HandleFunc("/jwt/", api.getJWT).Methods(http.MethodGet)
|
||||||
r.HandleFunc("/configuration/", api.updateConfiguration).Methods(http.MethodPost)
|
r.HandleFunc("/configuration/", api.updateConfiguration).Methods(http.MethodPost)
|
||||||
|
r.HandleFunc("/jobs/metrics/{id}", api.getJobMetrics).Methods(http.MethodGet) // Fetched in Job.svelte: Needs All-User-Access-Session-Auth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,27 +219,25 @@ func (auth *Authentication) Auth(
|
|||||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
user, err := auth.JwtAuth.AuthViaJWT(rw, r)
|
user, err := auth.JwtAuth.AuthViaJWT(rw, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Infof("authentication failed: %s", err.Error())
|
log.Infof("auth -> authentication failed: %s", err.Error())
|
||||||
http.Error(rw, err.Error(), http.StatusUnauthorized)
|
http.Error(rw, err.Error(), http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if user == nil {
|
if user == nil {
|
||||||
user, err = auth.AuthViaSession(rw, r)
|
user, err = auth.AuthViaSession(rw, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Infof("authentication failed: %s", err.Error())
|
log.Infof("auth -> authentication failed: %s", err.Error())
|
||||||
http.Error(rw, err.Error(), http.StatusUnauthorized)
|
http.Error(rw, err.Error(), http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if user != nil {
|
if user != nil {
|
||||||
ctx := context.WithValue(r.Context(), repository.ContextUserKey, user)
|
ctx := context.WithValue(r.Context(), repository.ContextUserKey, user)
|
||||||
onsuccess.ServeHTTP(rw, r.WithContext(ctx))
|
onsuccess.ServeHTTP(rw, r.WithContext(ctx))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug("authentication failed")
|
log.Info("auth -> authentication failed")
|
||||||
onfailure(rw, r, errors.New("unauthorized (please login first)"))
|
onfailure(rw, r, errors.New("unauthorized (please login first)"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -251,8 +249,8 @@ func (auth *Authentication) AuthApi(
|
|||||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
user, err := auth.JwtAuth.AuthViaJWT(rw, r)
|
user, err := auth.JwtAuth.AuthViaJWT(rw, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Infof("authentication failed: %s", err.Error())
|
log.Infof("auth api -> authentication failed: %s", err.Error())
|
||||||
http.Error(rw, err.Error(), http.StatusUnauthorized)
|
onfailure(rw, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if user != nil {
|
if user != nil {
|
||||||
@ -270,12 +268,12 @@ func (auth *Authentication) AuthApi(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
log.Debug("authentication failed")
|
log.Info("auth api -> authentication failed: missing role")
|
||||||
onfailure(rw, r, errors.New("unauthorized (missing role)"))
|
onfailure(rw, r, errors.New("unauthorized"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Debug("authentication failed")
|
log.Info("auth api -> authentication failed: no auth")
|
||||||
onfailure(rw, r, errors.New("unauthorized (no auth)"))
|
onfailure(rw, r, errors.New("unauthorized"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,8 +284,8 @@ func (auth *Authentication) AuthUserApi(
|
|||||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
user, err := auth.JwtAuth.AuthViaJWT(rw, r)
|
user, err := auth.JwtAuth.AuthViaJWT(rw, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Infof("authentication failed: %s", err.Error())
|
log.Infof("auth user api -> authentication failed: %s", err.Error())
|
||||||
http.Error(rw, err.Error(), http.StatusUnauthorized)
|
onfailure(rw, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if user != nil {
|
if user != nil {
|
||||||
@ -305,12 +303,12 @@ func (auth *Authentication) AuthUserApi(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
log.Debug("authentication failed")
|
log.Info("auth user api -> authentication failed: missing role")
|
||||||
onfailure(rw, r, errors.New("unauthorized (missing role)"))
|
onfailure(rw, r, errors.New("unauthorized"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Debug("authentication failed")
|
log.Info("auth user api -> authentication failed: no auth")
|
||||||
onfailure(rw, r, errors.New("unauthorized (no auth)"))
|
onfailure(rw, r, errors.New("unauthorized"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,8 +319,8 @@ func (auth *Authentication) AuthConfigApi(
|
|||||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
user, err := auth.AuthViaSession(rw, r)
|
user, err := auth.AuthViaSession(rw, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Infof("authentication failed: %s", err.Error())
|
log.Infof("auth config api -> authentication failed: %s", err.Error())
|
||||||
http.Error(rw, err.Error(), http.StatusUnauthorized)
|
onfailure(rw, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if user != nil && user.HasRole(schema.RoleAdmin) {
|
if user != nil && user.HasRole(schema.RoleAdmin) {
|
||||||
@ -330,20 +328,20 @@ func (auth *Authentication) AuthConfigApi(
|
|||||||
onsuccess.ServeHTTP(rw, r.WithContext(ctx))
|
onsuccess.ServeHTTP(rw, r.WithContext(ctx))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debug("authentication failed")
|
log.Info("auth config api -> authentication failed: no auth")
|
||||||
onfailure(rw, r, errors.New("unauthorized (no auth)"))
|
onfailure(rw, r, errors.New("unauthorized"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (auth *Authentication) AuthUserConfigApi(
|
func (auth *Authentication) AuthFrontendApi(
|
||||||
onsuccess http.Handler,
|
onsuccess http.Handler,
|
||||||
onfailure func(rw http.ResponseWriter, r *http.Request, authErr error),
|
onfailure func(rw http.ResponseWriter, r *http.Request, authErr error),
|
||||||
) http.Handler {
|
) http.Handler {
|
||||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
user, err := auth.AuthViaSession(rw, r)
|
user, err := auth.AuthViaSession(rw, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Infof("authentication failed: %s", err.Error())
|
log.Infof("auth frontend api -> authentication failed: %s", err.Error())
|
||||||
http.Error(rw, err.Error(), http.StatusUnauthorized)
|
onfailure(rw, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if user != nil {
|
if user != nil {
|
||||||
@ -351,8 +349,8 @@ func (auth *Authentication) AuthUserConfigApi(
|
|||||||
onsuccess.ServeHTTP(rw, r.WithContext(ctx))
|
onsuccess.ServeHTTP(rw, r.WithContext(ctx))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debug("authentication failed")
|
log.Info("auth frontend api -> authentication failed: no auth")
|
||||||
onfailure(rw, r, errors.New("unauthorized (no auth)"))
|
onfailure(rw, r, errors.New("unauthorized"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,16 +305,36 @@ func (r *JobRepository) FindByIdDirect(jobId int64) (*schema.Job, error) {
|
|||||||
return scanJob(q.RunWith(r.stmtCache).QueryRow())
|
return scanJob(q.RunWith(r.stmtCache).QueryRow())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindByJobId executes a SQL query to find a specific batch job.
|
||||||
|
// The job is queried using the slurm id and the clustername.
|
||||||
|
// It returns a pointer to a schema.Job data structure and an error variable.
|
||||||
|
// To check if no job was found test err == sql.ErrNoRows
|
||||||
|
func (r *JobRepository) FindByJobId(ctx context.Context, jobId int64, startTime int64, cluster string) (*schema.Job, error) {
|
||||||
|
q := sq.Select(jobColumns...).
|
||||||
|
From("job").
|
||||||
|
Where("job.job_id = ?", jobId).
|
||||||
|
Where("job.cluster = ?", cluster).
|
||||||
|
Where("job.start_time = ?", startTime)
|
||||||
|
|
||||||
|
q, qerr := SecurityCheck(ctx, q)
|
||||||
|
if qerr != nil {
|
||||||
|
return nil, qerr
|
||||||
|
}
|
||||||
|
|
||||||
|
return scanJob(q.RunWith(r.stmtCache).QueryRow())
|
||||||
|
}
|
||||||
|
|
||||||
// IsJobOwner executes a SQL query to find a specific batch job.
|
// IsJobOwner executes a SQL query to find a specific batch job.
|
||||||
// The job is queried using the slurm id,a username and the cluster.
|
// The job is queried using the slurm id,a username and the cluster.
|
||||||
// It returns a bool.
|
// It returns a bool.
|
||||||
// If job was found, user is owner: test err != sql.ErrNoRows
|
// If job was found, user is owner: test err != sql.ErrNoRows
|
||||||
func (r *JobRepository) IsJobOwner(jobId int64, user string, cluster string) bool {
|
func (r *JobRepository) IsJobOwner(jobId int64, startTime int64, user string, cluster string) bool {
|
||||||
q := sq.Select("id").
|
q := sq.Select("id").
|
||||||
From("job").
|
From("job").
|
||||||
Where("job.job_id = ?", jobId).
|
Where("job.job_id = ?", jobId).
|
||||||
Where("job.user = ?", user).
|
Where("job.user = ?", user).
|
||||||
Where("job.cluster = ?", cluster)
|
Where("job.cluster = ?", cluster).
|
||||||
|
Where("job.start_time = ?", startTime)
|
||||||
|
|
||||||
_, err := scanJob(q.RunWith(r.stmtCache).QueryRow())
|
_, err := scanJob(q.RunWith(r.stmtCache).QueryRow())
|
||||||
return err != sql.ErrNoRows
|
return err != sql.ErrNoRows
|
||||||
|
@ -262,7 +262,7 @@
|
|||||||
<form
|
<form
|
||||||
id="colorscheme-form"
|
id="colorscheme-form"
|
||||||
method="post"
|
method="post"
|
||||||
action="/userconfig/configuration/"
|
action="/frontend/configuration/"
|
||||||
class="card-body"
|
class="card-body"
|
||||||
>
|
>
|
||||||
<!-- Svelte 'class' directive only on DOMs directly, normal 'class="xxx"' does not work, so style-array it is. -->
|
<!-- Svelte 'class' directive only on DOMs directly, normal 'class="xxx"' does not work, so style-array it is. -->
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
<form
|
<form
|
||||||
id="line-width-form"
|
id="line-width-form"
|
||||||
method="post"
|
method="post"
|
||||||
action="/userconfig/configuration/"
|
action="/frontend/configuration/"
|
||||||
class="card-body"
|
class="card-body"
|
||||||
on:submit|preventDefault={() =>
|
on:submit|preventDefault={() =>
|
||||||
updateSetting("#line-width-form", "lw")}
|
updateSetting("#line-width-form", "lw")}
|
||||||
@ -76,7 +76,7 @@
|
|||||||
<form
|
<form
|
||||||
id="plots-per-row-form"
|
id="plots-per-row-form"
|
||||||
method="post"
|
method="post"
|
||||||
action="/userconfig/configuration/"
|
action="/frontend/configuration/"
|
||||||
class="card-body"
|
class="card-body"
|
||||||
on:submit|preventDefault={() =>
|
on:submit|preventDefault={() =>
|
||||||
updateSetting("#plots-per-row-form", "ppr")}
|
updateSetting("#plots-per-row-form", "ppr")}
|
||||||
@ -122,7 +122,7 @@
|
|||||||
<form
|
<form
|
||||||
id="backgrounds-form"
|
id="backgrounds-form"
|
||||||
method="post"
|
method="post"
|
||||||
action="/userconfig/configuration/"
|
action="/frontend/configuration/"
|
||||||
class="card-body"
|
class="card-body"
|
||||||
on:submit|preventDefault={() =>
|
on:submit|preventDefault={() =>
|
||||||
updateSetting("#backgrounds-form", "bg")}
|
updateSetting("#backgrounds-form", "bg")}
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
<form
|
<form
|
||||||
id="paging-form"
|
id="paging-form"
|
||||||
method="post"
|
method="post"
|
||||||
action="/userconfig/configuration/"
|
action="/frontend/configuration/"
|
||||||
class="card-body"
|
class="card-body"
|
||||||
on:submit|preventDefault={() =>
|
on:submit|preventDefault={() =>
|
||||||
updateSetting("#paging-form", "pag")}
|
updateSetting("#paging-form", "pag")}
|
||||||
|
@ -239,7 +239,7 @@ export async function fetchMetrics(job, metrics, scopes) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
let res = await fetch(
|
let res = await fetch(
|
||||||
`/api/jobs/metrics/${job.id}${query.length > 0 ? "?" : ""}${query.join(
|
`/frontend/jobs/metrics/${job.id}${query.length > 0 ? "?" : ""}${query.join(
|
||||||
"&"
|
"&"
|
||||||
)}`
|
)}`
|
||||||
);
|
);
|
||||||
@ -434,7 +434,7 @@ export function transformPerNodeDataForRoofline(nodes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchJwt(username) {
|
export async function fetchJwt(username) {
|
||||||
const raw = await fetch(`/userconfig/jwt/?username=${username}`);
|
const raw = await fetch(`/frontend/jwt/?username=${username}`);
|
||||||
|
|
||||||
if (!raw.ok) {
|
if (!raw.ok) {
|
||||||
const message = `An error has occured: ${response.status}`;
|
const message = `An error has occured: ${response.status}`;
|
||||||
|
Loading…
Reference in New Issue
Block a user