1
0
forked from baron/baron-sso

Devfront를 위한 OIDC 프록시 엔드포인트 구현

This commit is contained in:
2026-02-11 17:32:35 +09:00
parent 2f1caa7b03
commit 8415069c0a
3 changed files with 77 additions and 24 deletions

View File

@@ -489,6 +489,7 @@ func main() {
// Auth Proxy Routes // Auth Proxy Routes
auth := api.Group("/auth") auth := api.Group("/auth")
auth.All("/oidc/*", authHandler.ProxyOidc)
auth.Post("/enchanted-link/init", authHandler.InitEnchantedLink) auth.Post("/enchanted-link/init", authHandler.InitEnchantedLink)
auth.Post("/enchanted-link/poll", authHandler.PollEnchantedLink) auth.Post("/enchanted-link/poll", authHandler.PollEnchantedLink)
auth.Post("/magic-link/verify", authHandler.VerifyMagicLink) auth.Post("/magic-link/verify", authHandler.VerifyMagicLink)

View File

@@ -1526,7 +1526,7 @@ func (h *AuthHandler) PasswordLogin(c *fiber.Ctx) error {
loginID := strings.TrimSpace(req.LoginID) loginID := strings.TrimSpace(req.LoginID)
ale.LoginIDs["loginId"] = req.LoginID // 원문 ale.LoginIDs["loginId"] = req.LoginID // 원문
ale.LoginIDs["loginId_normalized"] = loginID ale.LoginIDs["loginId_normalized"] = loginID
ale.NewPassword = req.Password // For test only, logging password (sensitive) // ale.NewPassword = req.Password // For test only, logging password (sensitive)
ale.Log(slog.LevelInfo, "Attempting to login") ale.Log(slog.LevelInfo, "Attempting to login")
@@ -1568,22 +1568,25 @@ func (h *AuthHandler) PasswordLogin(c *fiber.Ctx) error {
// --- OIDC 로그인 흐름 처리 --- // --- OIDC 로그인 흐름 처리 ---
if req.LoginChallenge != "" { if req.LoginChallenge != "" {
slog.Info("OIDC login flow detected", "challenge", req.LoginChallenge) slog.Info("OIDC login flow detected", "challenge", req.LoginChallenge, "subject", subject)
// Check if the client is active // Check if the client is active
loginReq, err := h.Hydra.GetLoginRequest(c.Context(), req.LoginChallenge) loginReq, err := h.Hydra.GetLoginRequest(c.Context(), req.LoginChallenge)
if err == nil && loginReq != nil && loginReq.Client.Metadata != nil { if err == nil && loginReq != nil {
if status, ok := loginReq.Client.Metadata["status"].(string); ok { slog.Info("OIDC Client Info", "client_id", loginReq.Client.ClientID, "name", loginReq.Client.ClientName)
if strings.ToLower(status) == "inactive" { if loginReq.Client.Metadata != nil {
slog.Warn("Login rejected for inactive client in PasswordLogin", "client_id", loginReq.Client.ClientID) if status, ok := loginReq.Client.Metadata["status"].(string); ok {
return fiber.NewError(fiber.StatusForbidden, "The client application is disabled.") if strings.ToLower(status) == "inactive" {
slog.Warn("Login rejected for inactive client in PasswordLogin", "client_id", loginReq.Client.ClientID)
return fiber.NewError(fiber.StatusForbidden, "The client application is disabled.")
}
} }
} }
} }
acceptResp, err := h.Hydra.AcceptLoginRequest(c.Context(), req.LoginChallenge, subject) acceptResp, err := h.Hydra.AcceptLoginRequest(c.Context(), req.LoginChallenge, subject)
if err != nil { if err != nil {
slog.Error("failed to accept hydra login request", "error", err) slog.Error("failed to accept hydra login request", "error", err, "challenge", req.LoginChallenge)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to accept OIDC login request") return fiber.NewError(fiber.StatusInternalServerError, "Failed to accept OIDC login request")
} }
slog.Info("Hydra login request accepted", "redirectTo", acceptResp.RedirectTo) slog.Info("Hydra login request accepted", "redirectTo", acceptResp.RedirectTo)
@@ -2480,7 +2483,56 @@ func (h *AuthHandler) formatPhoneForStorage(phone string) string {
return phone return phone
} }
// GetMe - Returns current user's profile with enriched data from local DB // ProxyOidc - 프론트엔드의 OIDC 요청을 내부 Hydra 서비스로 프록시합니다.
func (h *AuthHandler) ProxyOidc(c *fiber.Ctx) error {
path := c.Params("*")
// [Strict] Always use internal Docker network address for proxying to avoid external loops
targetURL := "http://hydra:4444"
// 프록시 URL 구성
u, err := url.Parse(targetURL)
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "invalid hydra public url")
}
u.Path = strings.TrimRight(u.Path, "/") + "/" + path
u.RawQuery = string(c.Request().URI().QueryString())
slog.Debug("Proxying OIDC request", "from", c.Path(), "to", u.String())
// 요청 준비
req, err := http.NewRequestWithContext(c.Context(), c.Method(), u.String(), bytes.NewReader(c.Body()))
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "failed to create proxy request")
}
// 헤더 복사
c.Request().Header.VisitAll(func(key, value []byte) {
k := string(key)
if k != "Host" && k != "Connection" {
req.Header.Add(k, string(value))
}
})
// 요청 실행 (Hydra 내부 HttpClient 사용)
resp, err := h.Hydra.HttpClient().Do(req)
if err != nil {
return fiber.NewError(fiber.StatusServiceUnavailable, "hydra public api unavailable")
}
defer resp.Body.Close()
// 응답 헤더 복사
for k, values := range resp.Header {
for _, v := range values {
c.Set(k, v)
}
}
// 상태 코드 및 바디 설정
c.Status(resp.StatusCode)
_, err = io.Copy(c.Response().BodyWriter(), resp.Body)
return err
}
func (h *AuthHandler) GetMe(c *fiber.Ctx) error { func (h *AuthHandler) GetMe(c *fiber.Ctx) error {
profile, err := h.resolveCurrentProfile(c) profile, err := h.resolveCurrentProfile(c)
if err != nil { if err != nil {

View File

@@ -47,7 +47,7 @@ func (s *HydraAdminService) ListClients(ctx context.Context, limit, offset int)
return nil, err return nil, err
} }
resp, err := s.httpClient().Do(req) resp, err := s.HttpClient().Do(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -75,7 +75,7 @@ func (s *HydraAdminService) GetClient(ctx context.Context, clientID string) (*do
return nil, err return nil, err
} }
resp, err := s.httpClient().Do(req) resp, err := s.HttpClient().Do(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -114,7 +114,7 @@ func (s *HydraAdminService) PatchClientStatus(ctx context.Context, clientID, sta
} }
req.Header.Set("Content-Type", "application/json-patch+json") req.Header.Set("Content-Type", "application/json-patch+json")
resp, err := s.httpClient().Do(req) resp, err := s.HttpClient().Do(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -145,7 +145,7 @@ func (s *HydraAdminService) CreateClient(ctx context.Context, client domain.Hydr
} }
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
resp, err := s.httpClient().Do(req) resp, err := s.HttpClient().Do(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -174,7 +174,7 @@ func (s *HydraAdminService) UpdateClient(ctx context.Context, clientID string, c
} }
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
resp, err := s.httpClient().Do(req) resp, err := s.HttpClient().Do(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -202,7 +202,7 @@ func (s *HydraAdminService) DeleteClient(ctx context.Context, clientID string) e
return err return err
} }
resp, err := s.httpClient().Do(req) resp, err := s.HttpClient().Do(req)
if err != nil { if err != nil {
return err return err
} }
@@ -235,7 +235,7 @@ func (s *HydraAdminService) ListConsentSessions(ctx context.Context, subject, cl
return nil, err return nil, err
} }
resp, err := s.httpClient().Do(req) resp, err := s.HttpClient().Do(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -276,7 +276,7 @@ func (s *HydraAdminService) RevokeConsentSessions(ctx context.Context, subject,
return err return err
} }
resp, err := s.httpClient().Do(req) resp, err := s.HttpClient().Do(req)
if err != nil { if err != nil {
return err return err
} }
@@ -289,7 +289,7 @@ func (s *HydraAdminService) RevokeConsentSessions(ctx context.Context, subject,
return nil return nil
} }
func (s *HydraAdminService) httpClient() *http.Client { func (s *HydraAdminService) HttpClient() *http.Client {
if s.HTTPClient != nil { if s.HTTPClient != nil {
return s.HTTPClient return s.HTTPClient
} }
@@ -367,7 +367,7 @@ func (s *HydraAdminService) GetConsentRequest(ctx context.Context, challenge str
return nil, fmt.Errorf("hydra admin: create request for get consent failed: %w", err) return nil, fmt.Errorf("hydra admin: create request for get consent failed: %w", err)
} }
resp, err := s.httpClient().Do(req) resp, err := s.HttpClient().Do(req)
if err != nil { if err != nil {
return nil, fmt.Errorf("hydra admin: get consent request failed: %w", err) return nil, fmt.Errorf("hydra admin: get consent request failed: %w", err)
} }
@@ -407,7 +407,7 @@ func (s *HydraAdminService) RejectConsentRequest(ctx context.Context, challenge
} }
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
resp, err := s.httpClient().Do(req) resp, err := s.HttpClient().Do(req)
if err != nil { if err != nil {
return nil, fmt.Errorf("hydra admin: reject consent request failed: %w", err) return nil, fmt.Errorf("hydra admin: reject consent request failed: %w", err)
} }
@@ -449,7 +449,7 @@ func (s *HydraAdminService) RejectLoginRequest(ctx context.Context, challenge, e
} }
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
resp, err := s.httpClient().Do(req) resp, err := s.HttpClient().Do(req)
if err != nil { if err != nil {
return nil, fmt.Errorf("hydra admin: reject login request failed: %w", err) return nil, fmt.Errorf("hydra admin: reject login request failed: %w", err)
} }
@@ -484,7 +484,7 @@ func (s *HydraAdminService) GetLoginRequest(ctx context.Context, challenge strin
return nil, fmt.Errorf("hydra admin: create request for get login failed: %w", err) return nil, fmt.Errorf("hydra admin: create request for get login failed: %w", err)
} }
resp, err := s.httpClient().Do(req) resp, err := s.HttpClient().Do(req)
if err != nil { if err != nil {
return nil, fmt.Errorf("hydra admin: get login request failed: %w", err) return nil, fmt.Errorf("hydra admin: get login request failed: %w", err)
} }
@@ -532,7 +532,7 @@ func (s *HydraAdminService) AcceptConsentRequest(ctx context.Context, challenge
} }
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
resp, err := s.httpClient().Do(req) resp, err := s.HttpClient().Do(req)
if err != nil { if err != nil {
return nil, fmt.Errorf("hydra admin: accept consent request failed: %w", err) return nil, fmt.Errorf("hydra admin: accept consent request failed: %w", err)
} }
@@ -576,7 +576,7 @@ func (s *HydraAdminService) AcceptLoginRequest(ctx context.Context, challenge st
} }
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
resp, err := s.httpClient().Do(req) resp, err := s.HttpClient().Do(req)
if err != nil { if err != nil {
return nil, fmt.Errorf("hydra admin: accept login request failed: %w", err) return nil, fmt.Errorf("hydra admin: accept login request failed: %w", err)
} }