9992fb4ef1
Refactor the application to a Go-based architecture for improved performance and maintainability. Replace the Dockerfile to utilize a multi-stage build process, enhancing image efficiency. Implement comprehensive session store tests to ensure reliability and create new OAuth handlers for managing authentication efficiently. Update documentation to reflect these structural changes.
155 lines
3.9 KiB
Go
155 lines
3.9 KiB
Go
package handlers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"gitlab.com/unboundsoftware/auth0mock/store"
|
|
)
|
|
|
|
// ManagementHandler handles Auth0 Management API endpoints
|
|
type ManagementHandler struct {
|
|
userStore *store.UserStore
|
|
logger *slog.Logger
|
|
}
|
|
|
|
// NewManagementHandler creates a new management handler
|
|
func NewManagementHandler(userStore *store.UserStore, logger *slog.Logger) *ManagementHandler {
|
|
return &ManagementHandler{
|
|
userStore: userStore,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
// UserResponse represents the user response format
|
|
type UserResponse struct {
|
|
Email string `json:"email,omitempty"`
|
|
GivenName string `json:"given_name,omitempty"`
|
|
FamilyName string `json:"family_name,omitempty"`
|
|
UserID string `json:"user_id"`
|
|
Picture string `json:"picture,omitempty"`
|
|
}
|
|
|
|
// GetUsersByEmail handles GET /api/v2/users-by-email
|
|
func (h *ManagementHandler) GetUsersByEmail(w http.ResponseWriter, r *http.Request) {
|
|
email := r.URL.Query().Get("email")
|
|
|
|
h.logger.Debug("getting user by email", "email", email)
|
|
|
|
user, ok := h.userStore.GetByEmail(email)
|
|
if !ok {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode([]interface{}{})
|
|
return
|
|
}
|
|
|
|
response := []UserResponse{
|
|
{
|
|
Email: user.Email,
|
|
GivenName: user.GivenName,
|
|
FamilyName: user.FamilyName,
|
|
UserID: fmt.Sprintf("auth0|%s", user.UserID),
|
|
Picture: user.Picture,
|
|
},
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(response)
|
|
}
|
|
|
|
// CreateUser handles POST /api/v2/users
|
|
func (h *ManagementHandler) CreateUser(w http.ResponseWriter, r *http.Request) {
|
|
var req struct {
|
|
Email string `json:"email"`
|
|
GivenName string `json:"given_name"`
|
|
FamilyName string `json:"family_name"`
|
|
}
|
|
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if req.Email == "" {
|
|
http.Error(w, "Email is required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
user := &store.User{
|
|
Email: req.Email,
|
|
GivenName: req.GivenName,
|
|
FamilyName: req.FamilyName,
|
|
UserID: req.Email,
|
|
}
|
|
|
|
// Set defaults if not provided
|
|
if user.GivenName == "" {
|
|
user.GivenName = "Given"
|
|
}
|
|
if user.FamilyName == "" {
|
|
user.FamilyName = "Last"
|
|
}
|
|
|
|
h.userStore.Create(req.Email, user)
|
|
|
|
h.logger.Info("created user", "email", req.Email)
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(map[string]string{
|
|
"user_id": fmt.Sprintf("auth0|%s", req.Email),
|
|
})
|
|
}
|
|
|
|
// UpdateUser handles PATCH /api/v2/users/{userid}
|
|
func (h *ManagementHandler) UpdateUser(w http.ResponseWriter, r *http.Request) {
|
|
// Extract user ID from path - format: /api/v2/users/auth0|email@example.com
|
|
path := r.URL.Path
|
|
userID := strings.TrimPrefix(path, "/api/v2/users/")
|
|
|
|
// Strip "auth0|" prefix to get email
|
|
email := strings.TrimPrefix(userID, "auth0|")
|
|
|
|
h.logger.Debug("patching user", "userid", userID, "email", email)
|
|
|
|
var req struct {
|
|
GivenName string `json:"given_name"`
|
|
FamilyName string `json:"family_name"`
|
|
Picture string `json:"picture"`
|
|
}
|
|
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
updates := &store.User{
|
|
GivenName: req.GivenName,
|
|
FamilyName: req.FamilyName,
|
|
Picture: req.Picture,
|
|
}
|
|
|
|
_, ok := h.userStore.Update(email, updates)
|
|
if !ok {
|
|
http.Error(w, "User not found", http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
h.logger.Info("updated user", "email", email)
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(map[string]string{
|
|
"user_id": fmt.Sprintf("auth0|%s", email),
|
|
})
|
|
}
|
|
|
|
// PasswordChangeTicket handles POST /api/v2/tickets/password-change
|
|
func (h *ManagementHandler) PasswordChangeTicket(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(map[string]string{
|
|
"ticket": "https://some-url",
|
|
})
|
|
}
|