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 := api.Group("/auth")
auth.All("/oidc/*", authHandler.ProxyOidc)
auth.Post("/enchanted-link/init", authHandler.InitEnchantedLink)
auth.Post("/enchanted-link/poll", authHandler.PollEnchantedLink)
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)
ale.LoginIDs["loginId"] = req.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")
@@ -1568,22 +1568,25 @@ func (h *AuthHandler) PasswordLogin(c *fiber.Ctx) error {
// --- OIDC 로그인 흐름 처리 ---
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
loginReq, err := h.Hydra.GetLoginRequest(c.Context(), req.LoginChallenge)
if err == nil && loginReq != nil && loginReq.Client.Metadata != nil {
if status, ok := loginReq.Client.Metadata["status"].(string); ok {
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.")
if err == nil && loginReq != nil {
slog.Info("OIDC Client Info", "client_id", loginReq.Client.ClientID, "name", loginReq.Client.ClientName)
if loginReq.Client.Metadata != nil {
if status, ok := loginReq.Client.Metadata["status"].(string); ok {
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)
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")
}
slog.Info("Hydra login request accepted", "redirectTo", acceptResp.RedirectTo)
@@ -2480,7 +2483,56 @@ func (h *AuthHandler) formatPhoneForStorage(phone string) string {
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 {
profile, err := h.resolveCurrentProfile(c)
if err != nil {

View File

@@ -47,7 +47,7 @@ func (s *HydraAdminService) ListClients(ctx context.Context, limit, offset int)
return nil, err
}
resp, err := s.httpClient().Do(req)
resp, err := s.HttpClient().Do(req)
if err != nil {
return nil, err
}
@@ -75,7 +75,7 @@ func (s *HydraAdminService) GetClient(ctx context.Context, clientID string) (*do
return nil, err
}
resp, err := s.httpClient().Do(req)
resp, err := s.HttpClient().Do(req)
if err != nil {
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")
resp, err := s.httpClient().Do(req)
resp, err := s.HttpClient().Do(req)
if err != nil {
return nil, err
}
@@ -145,7 +145,7 @@ func (s *HydraAdminService) CreateClient(ctx context.Context, client domain.Hydr
}
req.Header.Set("Content-Type", "application/json")
resp, err := s.httpClient().Do(req)
resp, err := s.HttpClient().Do(req)
if err != nil {
return nil, err
}
@@ -174,7 +174,7 @@ func (s *HydraAdminService) UpdateClient(ctx context.Context, clientID string, c
}
req.Header.Set("Content-Type", "application/json")
resp, err := s.httpClient().Do(req)
resp, err := s.HttpClient().Do(req)
if err != nil {
return nil, err
}
@@ -202,7 +202,7 @@ func (s *HydraAdminService) DeleteClient(ctx context.Context, clientID string) e
return err
}
resp, err := s.httpClient().Do(req)
resp, err := s.HttpClient().Do(req)
if err != nil {
return err
}
@@ -235,7 +235,7 @@ func (s *HydraAdminService) ListConsentSessions(ctx context.Context, subject, cl
return nil, err
}
resp, err := s.httpClient().Do(req)
resp, err := s.HttpClient().Do(req)
if err != nil {
return nil, err
}
@@ -276,7 +276,7 @@ func (s *HydraAdminService) RevokeConsentSessions(ctx context.Context, subject,
return err
}
resp, err := s.httpClient().Do(req)
resp, err := s.HttpClient().Do(req)
if err != nil {
return err
}
@@ -289,7 +289,7 @@ func (s *HydraAdminService) RevokeConsentSessions(ctx context.Context, subject,
return nil
}
func (s *HydraAdminService) httpClient() *http.Client {
func (s *HydraAdminService) HttpClient() *http.Client {
if s.HTTPClient != nil {
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)
}
resp, err := s.httpClient().Do(req)
resp, err := s.HttpClient().Do(req)
if err != nil {
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")
resp, err := s.httpClient().Do(req)
resp, err := s.HttpClient().Do(req)
if err != nil {
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")
resp, err := s.httpClient().Do(req)
resp, err := s.HttpClient().Do(req)
if err != nil {
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)
}
resp, err := s.httpClient().Do(req)
resp, err := s.HttpClient().Do(req)
if err != nil {
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")
resp, err := s.httpClient().Do(req)
resp, err := s.HttpClient().Do(req)
if err != nil {
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")
resp, err := s.httpClient().Do(req)
resp, err := s.HttpClient().Do(req)
if err != nil {
return nil, fmt.Errorf("hydra admin: accept login request failed: %w", err)
}