diff options
Diffstat (limited to 'components/login/saml-login-button.tsx')
| -rw-r--r-- | components/login/saml-login-button.tsx | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/components/login/saml-login-button.tsx b/components/login/saml-login-button.tsx new file mode 100644 index 00000000..02825e2f --- /dev/null +++ b/components/login/saml-login-button.tsx @@ -0,0 +1,121 @@ +'use client' + +/** + * + * SAML 2.0 기반 SSO 로그인 요청을 시작하는 버튼 컴포넌트 + * + * + */ + +import { useState } from 'react' +import { Button } from '@/components/ui/button' +import { toast } from '@/hooks/use-toast' +import { Loader2, Shield } from 'lucide-react' +import React from 'react' + +interface SAMLLoginButtonProps { + className?: string + children?: React.ReactNode + variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link' | 'samsung' + size?: 'default' | 'sm' | 'lg' | 'icon' +} + +export function SAMLLoginButton({ + className, + children = "Knox SSO로 로그인하기", + variant = "outline", + size = "default" +}: SAMLLoginButtonProps) { + const [isLoading, setIsLoading] = useState(false) + + const handleSAMLLogin = async () => { + try { + setIsLoading(true) + + // 현재 페이지 경로를 RelayState로 설정 (로그인 후 이 페이지로 돌아옴) + const currentPath = window.location.pathname + window.location.search + const relayState = encodeURIComponent(currentPath) + + console.log('Setting RelayState to:', currentPath) + + // API 엔드포인트를 통해 SAML AuthnRequest URL 생성 + const response = await fetch(`/api/auth/saml/authn-request?relayState=${relayState}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }) + + if (!response.ok) { + throw new Error('Failed to create SAML AuthnRequest') + } + + const data = await response.json() + + if (!data.success || !data.loginUrl) { + throw new Error(data.error || 'Failed to get SAML login URL') + } + + console.log('SAML Login URL:', data.loginUrl) + + // data URL인지 확인 (브라우저 보안 정책으로 차단될 수 있음) + if (data.loginUrl.startsWith('data:')) { + console.warn('⚠️ Data URL detected - this may be blocked by browser security policies') + toast({ + title: '테스트 모드 감지', + description: 'Mock SAML IdP 모드가 활성화되어 있습니다. 프로덕션에서는 SAML_MOCKING_IDP=false로 설정하세요.', + variant: 'default', + }) + + // data URL 대신 Mock IdP 페이지로 직접 리다이렉트 + const baseUrl = window.location.origin + const mockIdpUrl = `${baseUrl}/api/auth/saml/mock-idp` + console.log('🎭 Redirecting to Mock IdP instead:', mockIdpUrl) + window.location.href = mockIdpUrl + return + } + + // 일반적인 URL로 리다이렉트 + window.location.href = data.loginUrl + + } catch (error) { + console.error('SAML Login Error:', error) + toast({ + title: '로그인 오류', + description: 'SAML 로그인을 시작할 수 없습니다.', + variant: 'destructive', + }) + setIsLoading(false) + } + } + + return ( + <Button + type="button" + variant={variant} + size={size} + className={className} + onClick={handleSAMLLogin} + disabled={isLoading} + > + {isLoading ? ( + <Loader2 className="h-4 w-4 animate-spin mr-2" /> + ) : ( + <Shield className="h-4 w-4 mr-2" /> + )} + {children} + </Button> + ) +} + +// 간단한 Knox SSO 버튼 (props 없이) +export function KnoxSSOButton() { + return ( + <SAMLLoginButton + className="w-full" + variant="outline" + > + Knox SSO (STAGE 단계) + </SAMLLoginButton> + ) +} |
