implemented simple ssh dual control
This commit is contained in:
parent
690613cab8
commit
60012be942
12 changed files with 446 additions and 20 deletions
|
|
@ -14,6 +14,7 @@ import (
|
|||
|
||||
type ContextData struct {
|
||||
Approver *Approver
|
||||
SSH *SSH
|
||||
DB *db.DB
|
||||
}
|
||||
|
||||
|
|
@ -97,6 +98,10 @@ func (c *Context) Approver() *Approver {
|
|||
return c.data.Approver
|
||||
}
|
||||
|
||||
func (c *Context) SSH() *SSH {
|
||||
return c.data.SSH
|
||||
}
|
||||
|
||||
// OK is a empty HTTP 200 JSON response
|
||||
func (c *Context) OK() {
|
||||
c.log()
|
||||
|
|
|
|||
|
|
@ -43,15 +43,17 @@ func newError(err string, code int) Error {
|
|||
}
|
||||
|
||||
var (
|
||||
ErrInvalidAPIRoute = newError("invalid api route", http.StatusNotFound)
|
||||
ErrInvalid = newError("invalid data", http.StatusBadRequest)
|
||||
ErrBadreq = newError("bad request", http.StatusBadRequest)
|
||||
ErrForbidden = newError("forbidden", http.StatusForbidden)
|
||||
ErrNotFound = newError("not found", http.StatusNotFound)
|
||||
ErrKeyNotFound = newError("key not found", http.StatusNotFound)
|
||||
ErrReqNotFound = newError("key request not found", http.StatusNotFound)
|
||||
ErrTooManyApprovals = newError("too many approvals pending", http.StatusConflict)
|
||||
ErrKeyRequestRejected = newError("key request rejected", http.StatusForbidden)
|
||||
ErrMNA = newError("method not allowed", http.StatusMethodNotAllowed)
|
||||
ErrISE = newError("internal server error", http.StatusInternalServerError)
|
||||
ErrInvalidAPIRoute = newError("invalid api route", http.StatusNotFound)
|
||||
ErrInvalid = newError("invalid data", http.StatusBadRequest)
|
||||
ErrBadreq = newError("bad request", http.StatusBadRequest)
|
||||
ErrForbidden = newError("forbidden", http.StatusForbidden)
|
||||
ErrNotFound = newError("not found", http.StatusNotFound)
|
||||
ErrKeyNotFound = newError("key not found", http.StatusNotFound)
|
||||
ErrReqNotFound = newError("key request not found", http.StatusNotFound)
|
||||
ErrAccessReqNotFound = newError("ssh request not found", http.StatusNotFound)
|
||||
ErrTooManyApprovals = newError("too many approvals pending", http.StatusConflict)
|
||||
ErrKeyRequestRejected = newError("key request rejected", http.StatusForbidden)
|
||||
ErrAccessRequestRejected = newError("ssh request rejected", http.StatusForbidden)
|
||||
ErrMNA = newError("method not allowed", http.StatusMethodNotAllowed)
|
||||
ErrISE = newError("internal server error", http.StatusInternalServerError)
|
||||
)
|
||||
|
|
|
|||
99
pkg/api/types/ssh.go
Normal file
99
pkg/api/types/ssh.go
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright (C) 2023 Marius Schellenberger
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.giftfish.de/ston1th/keyctl/pkg/key"
|
||||
)
|
||||
|
||||
type SSHMap map[string]SSHAccess
|
||||
|
||||
type SSH struct {
|
||||
// protects m
|
||||
mu sync.RWMutex
|
||||
|
||||
m SSHMap
|
||||
}
|
||||
|
||||
func NewSSH() *SSH {
|
||||
return &SSH{
|
||||
m: make(SSHMap),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SSH) New(host, user, ip string) (aid string, err error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
size := len(s.m)
|
||||
if size > maxSize {
|
||||
err = ErrTooManyApprovals
|
||||
return
|
||||
}
|
||||
aid, err = key.GenerateID()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
s.m[aid] = SSHAccess{
|
||||
Host: host,
|
||||
User: user,
|
||||
IP: ip,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *SSH) List() (m SSHMap) {
|
||||
s.mu.RLock()
|
||||
m = maps.Clone(s.m)
|
||||
s.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
func (s *SSH) Status(aid, host, user, ip string) (status Status) {
|
||||
s.mu.RLock()
|
||||
if app, ok := s.m[aid]; ok {
|
||||
if app.Host == host && app.IP == ip && app.User == user {
|
||||
status = app.Status
|
||||
} else {
|
||||
status = Rejected
|
||||
}
|
||||
} else {
|
||||
status = NotFound
|
||||
}
|
||||
s.mu.RUnlock()
|
||||
if status == Approved || status == Rejected {
|
||||
s.mu.Lock()
|
||||
delete(s.m, aid)
|
||||
s.mu.Unlock()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *SSH) Update(aid string, status Status) (err error) {
|
||||
s.mu.Lock()
|
||||
if app, ok := s.m[aid]; ok {
|
||||
app.Status = status
|
||||
s.m[aid] = app
|
||||
go s.cleanup(aid)
|
||||
} else {
|
||||
err = ErrAccessReqNotFound
|
||||
}
|
||||
s.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (s *SSH) cleanup(aid string) {
|
||||
time.Sleep(time.Second * 10)
|
||||
s.mu.Lock()
|
||||
delete(s.m, aid)
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
type SSHAccess struct {
|
||||
Host string
|
||||
User string
|
||||
IP string
|
||||
Status Status
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue