polycule-connect/polyculeconnect/controller/auth/authcallback.go

100 lines
3.3 KiB
Go
Raw Normal View History

package auth
import (
"net/http"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/helpers"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/model"
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/storage"
"github.com/google/uuid"
"github.com/zitadel/oidc/v3/pkg/client/rp"
"github.com/zitadel/oidc/v3/pkg/oidc"
"go.uber.org/zap"
)
const AuthCallbackRoute = "/callback"
type AuthCallbackController struct {
l *zap.SugaredLogger
st *storage.Storage
}
func NewAuthCallbackController(l *zap.SugaredLogger, st *storage.Storage) *AuthCallbackController {
return &AuthCallbackController{
l: l,
st: st,
}
}
func (c *AuthCallbackController) HandleUserInfoCallback(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens[*oidc.IDTokenClaims], state string, rp rp.RelyingParty, info *oidc.UserInfo) {
requestID, err := uuid.Parse(state)
if err != nil {
c.l.Errorf("Invalid state, should be a request UUID, but got %s: %s", state, err)
helpers.HandleResponse(w, r, http.StatusInternalServerError, []byte("failed to perform authentication"), c.l)
return
}
c.l.Infof("Successful login from %s", info.Email)
user := model.User{
ID: uuid.New(),
Email: info.Email,
Username: info.PreferredUsername,
}
err = c.st.LocalStorage.AuthRequestStorage().ValidateAuthRequest(r.Context(), requestID, &user)
if err != nil {
c.l.Errorf("Failed to validate auth request from storage: %s", err)
helpers.HandleResponse(w, r, http.StatusInternalServerError, []byte("failed to perform authentication"), c.l)
return
}
http.Redirect(w, r, "/authorize/callback?id="+state, http.StatusFound)
}
type CallbackDispatchController struct {
l *zap.SugaredLogger
st *storage.Storage
callbackHandlers map[uuid.UUID]http.Handler
}
func NewCallbackDispatchController(l *zap.SugaredLogger, st *storage.Storage, handlers map[uuid.UUID]http.Handler) *CallbackDispatchController {
return &CallbackDispatchController{
l: l,
st: st,
callbackHandlers: handlers,
}
}
func (c *CallbackDispatchController) ServeHTTP(w http.ResponseWriter, r *http.Request) {
errMsg := r.URL.Query().Get("error")
if errMsg != "" {
errorDesc := r.URL.Query().Get("error_description")
c.l.Errorf("Failed to perform authentication: %s (%s)", errMsg, errorDesc)
helpers.HandleResponse(w, r, http.StatusInternalServerError, []byte("failed to perform authentication"), c.l)
return
}
state := r.URL.Query().Get("state")
requestID, err := uuid.Parse(state)
if err != nil {
c.l.Errorf("Invalid state, should be a request UUID, but got %s: %s", state, err)
helpers.HandleResponse(w, r, http.StatusInternalServerError, []byte("failed to perform authentication"), c.l)
return
}
req, err := c.st.LocalStorage.AuthRequestStorage().GetAuthRequestByID(r.Context(), requestID)
if err != nil {
c.l.Errorf("Failed to get auth request from DB: %s", err)
helpers.HandleResponse(w, r, http.StatusBadRequest, []byte("unknown request id"), c.l)
return
}
callbackHandler, ok := c.callbackHandlers[req.BackendID]
if !ok {
c.l.Errorf("Backend %s does not exist for request %s", req.ID, req.BackendID)
helpers.HandleResponse(w, r, http.StatusNotFound, []byte("unknown backend"), c.l)
return
}
callbackHandler.ServeHTTP(w, r)
}