kereru-forms/backend/internal/api/auth_handler.go

122 lines
3.3 KiB
Go
Raw Permalink Normal View History

2026-10-23 19:36:02 +00:00
package api
import (
"context"
"errors"
"github.com/gin-gonic/gin"
openapi_types "github.com/oapi-codegen/runtime/types"
"kereru.forms/internal/auth"
)
func (s *Server) GetAuthConfig(ctx context.Context, _ GetAuthConfigRequestObject) (GetAuthConfigResponseObject, error) {
_, span := s.tracer.Start(ctx, "GetAuthConfig")
defer span.End()
if s.auth == nil {
return GetAuthConfig200JSONResponse(AuthConfig{
Mode: AuthConfigMode("password"),
}), nil
}
cfg := s.auth.PublicConfig()
out := AuthConfig{
Mode: AuthConfigMode(cfg.Mode),
RequireSubmissionAuth: cfg.RequireSubmissionAuth,
}
if cfg.OIDC != nil {
out.Oidc = &OIDCClientConfig{
IssuerUrl: cfg.OIDC.IssuerURL,
AuthorizationEndpoint: cfg.OIDC.AuthorizationEndpoint,
TokenEndpoint: cfg.OIDC.TokenEndpoint,
ClientId: cfg.OIDC.ClientID,
Scopes: cfg.OIDC.Scopes,
}
}
return GetAuthConfig200JSONResponse(out), nil
}
func (s *Server) Login(ctx context.Context, request LoginRequestObject) (LoginResponseObject, error) {
_, span := s.tracer.Start(ctx, "Login")
defer span.End()
if s.auth == nil {
return Login400JSONResponse{ErrorJSONResponse: errJSON("authentication is not configured", "auth_not_configured")}, nil
}
if request.Body == nil {
return Login400JSONResponse{ErrorJSONResponse: errJSON("password is required", "invalid_request")}, nil
}
token, user, err := s.auth.Login(request.Body.Password)
switch {
case errors.Is(err, auth.ErrLocalLoginDisabled):
return Login400JSONResponse{ErrorJSONResponse: errJSON("local password login is disabled", "local_login_disabled")}, nil
case errors.Is(err, auth.ErrInvalidCredentials):
return Login401JSONResponse(Error{
Error: "invalid credentials",
Code: stringPtr("invalid_credentials"),
}), nil
case err != nil:
s.logger.Error().Err(err).Msg("local login")
return Login400JSONResponse{ErrorJSONResponse: errJSON("could not sign in", "internal_error")}, nil
default:
return Login200JSONResponse(LoginResponse{
Token: token,
User: toAPIAuthUser(user),
}), nil
}
}
func (s *Server) GetCurrentUser(ctx context.Context, _ GetCurrentUserRequestObject) (GetCurrentUserResponseObject, error) {
_, span := s.tracer.Start(ctx, "GetCurrentUser")
defer span.End()
ginCtx, ok := ctx.(*gin.Context)
if !ok {
return GetCurrentUser401JSONResponse{ErrorJSONResponse: errJSON("authentication required", "unauthenticated")}, nil
}
user, ok := CurrentUser(ginCtx)
if !ok {
return GetCurrentUser401JSONResponse{ErrorJSONResponse: errJSON("authentication required", "unauthenticated")}, nil
}
return GetCurrentUser200JSONResponse(AuthMeResponse{
Authenticated: true,
User: authUserPtr(toAPIAuthUser(user)),
}), nil
}
func (s *Server) Logout(context.Context, LogoutRequestObject) (LogoutResponseObject, error) {
return Logout204Response{}, nil
}
func toAPIAuthUser(user auth.User) AuthUser {
roles := user.Roles
if roles == nil {
roles = []string{}
}
out := AuthUser{
Id: user.ID,
Roles: roles,
CanAdmin: user.CanAdmin,
CanView: user.CanView,
}
if user.Name != "" {
name := user.Name
out.Name = &name
}
if user.Email != "" {
email := openapi_types.Email(user.Email)
out.Email = &email
}
return out
}
func authUserPtr(user AuthUser) *AuthUser {
return &user
}
func stringPtr(value string) *string {
return &value
}