forked from baron/baron-sso
Devfront를 위한 OIDC 프록시 엔드포인트 구현
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user