summaryrefslogtreecommitdiff
path: root/components/login/saml-login-button.tsx
blob: b92015fd34e0e6ee005aa82fca21eb7f8f10a3e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
'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'
}

const isSsoStage = process.env.SAML_IDP_SSO_URL?.includes('stage');

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"
    >
      {isSsoStage ? 'Knox SSO (STAGE)' : 'Knox SSO'}
    </SAMLLoginButton>
  )
}