93 lines
2.0 KiB
Go
93 lines
2.0 KiB
Go
package agent
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"forge.cadoles.com/Cadoles/emissary/internal/auth"
|
|
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
|
"github.com/lestrrat-go/jwx/v2/jws"
|
|
"github.com/lestrrat-go/jwx/v2/jwt"
|
|
"github.com/pkg/errors"
|
|
"gitlab.com/wpetit/goweb/logger"
|
|
)
|
|
|
|
type Authenticator struct {
|
|
repo datastore.AgentRepository
|
|
}
|
|
|
|
// Authenticate implements auth.Authenticator.
|
|
func (a *Authenticator) Authenticate(ctx context.Context, r *http.Request) (auth.User, error) {
|
|
ctx = logger.With(r.Context(), logger.F("remoteAddr", r.RemoteAddr))
|
|
|
|
authorization := r.Header.Get("Authorization")
|
|
if authorization == "" {
|
|
return nil, errors.WithStack(auth.ErrUnauthenticated)
|
|
}
|
|
|
|
rawToken := strings.TrimPrefix(authorization, "Bearer ")
|
|
if rawToken == "" {
|
|
return nil, errors.WithStack(auth.ErrUnauthenticated)
|
|
}
|
|
|
|
token, err := jwt.Parse([]byte(rawToken), jwt.WithVerify(false))
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
rawThumbprint, exists := token.Get(keyThumbprint)
|
|
if !exists {
|
|
return nil, errors.Errorf("could not find '%s' claim", keyThumbprint)
|
|
}
|
|
|
|
thumbrint, ok := rawThumbprint.(string)
|
|
if !ok {
|
|
return nil, errors.Errorf("unexpected '%s' claim value: '%v'", keyThumbprint, rawThumbprint)
|
|
}
|
|
|
|
agents, _, err := a.repo.Query(
|
|
ctx,
|
|
datastore.WithAgentQueryThumbprints(thumbrint),
|
|
datastore.WithAgentQueryLimit(1),
|
|
)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
if len(agents) != 1 {
|
|
return nil, errors.Errorf("unexpected number of found agents: '%d'", len(agents))
|
|
}
|
|
|
|
agent, err := a.repo.Get(
|
|
ctx,
|
|
agents[0].ID,
|
|
)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
_, err = jwt.Parse(
|
|
[]byte(rawToken),
|
|
jwt.WithKeySet(agent.KeySet.Set, jws.WithRequireKid(false)),
|
|
jwt.WithValidate(true),
|
|
)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
user := &User{
|
|
agent: agent,
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
func NewAuthenticator(repo datastore.AgentRepository) *Authenticator {
|
|
return &Authenticator{
|
|
repo: repo,
|
|
}
|
|
}
|
|
|
|
var _ auth.Authenticator = &Authenticator{}
|