Compare commits
5 Commits
2024.3.1-s
...
2024.3.4-s
Author | SHA1 | Date | |
---|---|---|---|
0b34b485da | |||
ab08d30d2a | |||
f6ffb68c43 | |||
4a1a434556 | |||
76718722cc |
@ -1,6 +1,7 @@
|
|||||||
package agent
|
package agent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/auth"
|
"forge.cadoles.com/Cadoles/emissary/internal/auth"
|
||||||
@ -29,4 +30,18 @@ func (u *User) Agent() *datastore.Agent {
|
|||||||
return u.agent
|
return u.agent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *User) MarshalJSON() ([]byte, error) {
|
||||||
|
type user struct {
|
||||||
|
Subject string `json:"subject"`
|
||||||
|
Tenant string `json:"tenant"`
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonUser := user{
|
||||||
|
Subject: u.Subject(),
|
||||||
|
Tenant: string(u.Tenant()),
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(jsonUser)
|
||||||
|
}
|
||||||
|
|
||||||
var _ auth.User = &User{}
|
var _ auth.User = &User{}
|
||||||
|
@ -64,16 +64,16 @@ func Middleware(authenticators ...Authenticator) func(http.Handler) http.Handler
|
|||||||
}
|
}
|
||||||
|
|
||||||
if user == nil {
|
if user == nil {
|
||||||
isUnauthorized, isUnauthenticated, isUnknown := checkErrors(errs)
|
hasUnauthorized, hasUnauthenticated, hasUnknown := checkErrors(errs)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case isUnauthorized && !isUnknown:
|
case hasUnauthorized && !hasUnknown:
|
||||||
api.ErrorResponse(w, http.StatusForbidden, api.ErrCodeForbidden, nil)
|
api.ErrorResponse(w, http.StatusForbidden, api.ErrCodeForbidden, nil)
|
||||||
return
|
return
|
||||||
case isUnauthenticated && !isUnknown:
|
case hasUnauthenticated && !hasUnknown:
|
||||||
api.ErrorResponse(w, http.StatusForbidden, api.ErrCodeForbidden, nil)
|
api.ErrorResponse(w, http.StatusUnauthorized, api.ErrCodeUnauthorized, nil)
|
||||||
return
|
return
|
||||||
case isUnknown:
|
case hasUnknown:
|
||||||
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
|
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
@ -101,10 +101,8 @@ func checkErrors(errs []error) (isUnauthorized bool, isUnauthenticated bool, isU
|
|||||||
switch {
|
switch {
|
||||||
case errors.Is(e, ErrUnauthorized):
|
case errors.Is(e, ErrUnauthorized):
|
||||||
isUnauthorized = true
|
isUnauthorized = true
|
||||||
continue
|
|
||||||
case errors.Is(e, ErrUnauthenticated):
|
case errors.Is(e, ErrUnauthenticated):
|
||||||
isUnauthenticated = true
|
isUnauthenticated = true
|
||||||
continue
|
|
||||||
default:
|
default:
|
||||||
isUnknown = true
|
isUnknown = true
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/auth"
|
"forge.cadoles.com/Cadoles/emissary/internal/auth"
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||||
)
|
)
|
||||||
@ -39,4 +41,20 @@ func (u *User) Role() Role {
|
|||||||
return u.role
|
return u.role
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *User) MarshalJSON() ([]byte, error) {
|
||||||
|
type user struct {
|
||||||
|
Subject string `json:"subject"`
|
||||||
|
Tenant string `json:"tenant"`
|
||||||
|
Role string `json:"role"`
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonUser := user{
|
||||||
|
Subject: u.Subject(),
|
||||||
|
Tenant: string(u.Tenant()),
|
||||||
|
Role: string(u.Role()),
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(jsonUser)
|
||||||
|
}
|
||||||
|
|
||||||
var _ auth.User = &User{}
|
var _ auth.User = &User{}
|
||||||
|
@ -183,7 +183,7 @@ func assertMatchingAgent() assertAgent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
agent := u.Agent()
|
agent := u.Agent()
|
||||||
if agent != nil && agent.ID == agentID {
|
if agent != nil && agent.ID == agentID && agent.Status == datastore.AgentStatusAccepted {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
35
internal/server/api/get_session.go
Normal file
35
internal/server/api/get_session.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"forge.cadoles.com/Cadoles/emissary/internal/auth"
|
||||||
|
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gitlab.com/wpetit/goweb/api"
|
||||||
|
"gitlab.com/wpetit/goweb/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *Mount) getSession(w http.ResponseWriter, r *http.Request) {
|
||||||
|
user, ok := assertRequestUser(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := r.Context()
|
||||||
|
|
||||||
|
tenant, err := m.tenantRepo.Get(ctx, user.Tenant())
|
||||||
|
if err != nil && !errors.Is(err, datastore.ErrNotFound) {
|
||||||
|
err = errors.WithStack(err)
|
||||||
|
logger.Error(ctx, "could not retrieve user tenant", logger.CapturedE(err))
|
||||||
|
api.ErrorResponse(w, http.StatusInternalServerError, ErrCodeUnknownError, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
api.DataResponse(w, http.StatusOK, struct {
|
||||||
|
User auth.User `json:"user"`
|
||||||
|
Tenant *datastore.Tenant `json:"tenant"`
|
||||||
|
}{
|
||||||
|
User: user,
|
||||||
|
Tenant: tenant,
|
||||||
|
})
|
||||||
|
}
|
@ -23,6 +23,8 @@ func (m *Mount) Mount(r chi.Router) {
|
|||||||
r.Group(func(r chi.Router) {
|
r.Group(func(r chi.Router) {
|
||||||
r.Use(auth.Middleware(m.authenticators...))
|
r.Use(auth.Middleware(m.authenticators...))
|
||||||
|
|
||||||
|
r.Get("/session", m.getSession)
|
||||||
|
|
||||||
r.Route("/agents", func(r chi.Router) {
|
r.Route("/agents", func(r chi.Router) {
|
||||||
r.With(assertUserWithWriteAccess).Post("/claim", m.claimAgent)
|
r.With(assertUserWithWriteAccess).Post("/claim", m.claimAgent)
|
||||||
|
|
||||||
|
@ -50,8 +50,8 @@ func (m *Mount) registerAgent(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !validSignature {
|
if !validSignature {
|
||||||
logger.Warn(ctx, "conflicting signature", logger.F("signature", registerAgentReq.Signature))
|
logger.Warn(ctx, "invalid thumbprint signature", logger.F("signature", registerAgentReq.Signature))
|
||||||
api.ErrorResponse(w, http.StatusConflict, ErrCodeConflict, nil)
|
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeInvalidRequest, nil)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -109,29 +109,39 @@ func (m *Mount) registerAgent(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
validSignature, err = jwk.Verify(agent.KeySet.Set, registerAgentReq.Signature, registerAgentReq.Thumbprint, registerAgentReq.Metadata)
|
if agent.Status != datastore.AgentStatusForgotten {
|
||||||
if err != nil {
|
validSignature, err = jwk.Verify(agent.KeySet.Set, registerAgentReq.Signature, registerAgentReq.Thumbprint, registerAgentReq.Metadata)
|
||||||
err = errors.WithStack(err)
|
if err != nil {
|
||||||
logger.Error(ctx, "could not validate signature using previous keyset", logger.CapturedE(err))
|
err = errors.WithStack(err)
|
||||||
|
logger.Error(ctx, "could not validate signature using previous keyset", logger.CapturedE(err))
|
||||||
|
|
||||||
api.ErrorResponse(w, http.StatusConflict, ErrCodeConflict, nil)
|
api.ErrorResponse(w, http.StatusConflict, ErrCodeConflict, nil)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !validSignature {
|
||||||
|
logger.Error(ctx, "invalid signature")
|
||||||
|
api.ErrorResponse(w, http.StatusConflict, ErrCodeConflict, nil)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !validSignature {
|
updates := []datastore.AgentUpdateOptionFunc{
|
||||||
logger.Error(ctx, "invalid signature")
|
datastore.WithAgentUpdateKeySet(keySet),
|
||||||
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeInvalidRequest, nil)
|
datastore.WithAgentUpdateMetadata(metadata),
|
||||||
|
datastore.WithAgentUpdateThumbprint(registerAgentReq.Thumbprint),
|
||||||
|
}
|
||||||
|
|
||||||
return
|
if agent.Status == datastore.AgentStatusForgotten {
|
||||||
|
updates = append(updates, datastore.WithAgentUpdateStatus(datastore.AgentStatusPending))
|
||||||
}
|
}
|
||||||
|
|
||||||
agent, err = m.agentRepo.Update(
|
agent, err = m.agentRepo.Update(
|
||||||
ctx,
|
ctx,
|
||||||
agents[0].ID,
|
agents[0].ID,
|
||||||
datastore.WithAgentUpdateKeySet(keySet),
|
updates...,
|
||||||
datastore.WithAgentUpdateMetadata(metadata),
|
|
||||||
datastore.WithAgentUpdateThumbprint(registerAgentReq.Thumbprint),
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.WithStack(err)
|
err = errors.WithStack(err)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
PRAGMA foreign_keys = 0;
|
||||||
|
|
||||||
CREATE TABLE tenants (
|
CREATE TABLE tenants (
|
||||||
id TEXT PRIMARY KEY,
|
id TEXT PRIMARY KEY,
|
||||||
label TEXT NOT NULL,
|
label TEXT NOT NULL,
|
||||||
@ -50,3 +52,5 @@ CREATE TABLE specs
|
|||||||
INSERT INTO specs SELECT id, agent_id, name, revision, data, created_at, updated_at, 0 FROM _specs;
|
INSERT INTO specs SELECT id, agent_id, name, revision, data, created_at, updated_at, 0 FROM _specs;
|
||||||
|
|
||||||
DROP TABLE _specs;
|
DROP TABLE _specs;
|
||||||
|
|
||||||
|
PRAGMA foreign_keys = 1;
|
@ -5,6 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -95,12 +96,15 @@ func (c *Client) apiDo(ctx context.Context, method string, path string, payload
|
|||||||
|
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
|
|
||||||
decoder := json.NewDecoder(res.Body)
|
data, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
if err := decoder.Decode(&response); err != nil {
|
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &response); err != nil {
|
||||||
|
return errors.Wrapf(err, "could not parse json: got '%s'", data)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user