summaryrefslogtreecommitdiff
path: root/app/api/auth/saml/authn-request/route.ts
blob: 6544a7652711aac492f15e27825ffdeed1feeb3d (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
/**
 * SAML 2.0 SSO AuthnRequest 생성 API
 * 
 * 역할:
 * - 프론트엔드에서 SAML 로그인 URL을 요청할 때 사용
 * - SAML AuthnRequest를 생성하고 IdP 로그인 URL 반환
 * - Mock 모드 지원으로 개발/테스트 환경에서 시뮬레이션 가능
 * 
 * 플로우:
 * 1. 사용자가 "Knox SSO로 로그인" 버튼 클릭
 * 2. 프론트엔드에서 이 API 호출
 * 3. SAML AuthnRequest URL 생성 후 반환
 * 4. 프론트엔드에서 해당 URL로 리다이렉트
 * 5. IdP에서 인증 후 /api/saml/callback으로 SAML Response 전송
 */

import { NextResponse } from 'next/server'
import { createAuthnRequest } from '../../[...nextauth]/saml/utils'
import { debugLog, debugError, debugSuccess, debugProcess } from '@/lib/debug-utils'

// SAML 환경변수 상태 체크
function validateSAMLEnvironment() {
  const samlEnvironment = {
    NODE_ENV: process.env.NODE_ENV,
    SAML_MOCKING_IDP: process.env.SAML_MOCKING_IDP,
    NEXTAUTH_URL: process.env.NEXTAUTH_URL,
    SAML_SP_PRIVATE_KEY: process.env.SAML_SP_PRIVATE_KEY ? '✅ Set' : '❌ Missing',
    SAML_SP_CERT: process.env.SAML_SP_CERT ? '✅ Set' : '❌ Missing',
  }

  debugLog('📊 SAML Environment check:', JSON.stringify(samlEnvironment, null, 2))

  // 필수 환경변수 검증
  const missingVars = []
  if (!process.env.NEXTAUTH_URL) missingVars.push('NEXTAUTH_URL')

  // 키 없어도 구현 가능해서 주석 처리함.
  // if (!process.env.SAML_SP_PRIVATE_KEY) missingVars.push('SAML_SP_PRIVATE_KEY')
  // if (!process.env.SAML_SP_CERT) missingVars.push('SAML_SP_CERT')

  if (missingVars.length > 0) {
    throw new Error(`Missing required SAML environment variables: ${missingVars.join(', ')}`)
  }

  return samlEnvironment
}

/**
 * SAML AuthnRequest URL 생성 엔드포인트
 * 
 * @returns {JSON} { loginUrl: string, success: boolean, isThisMocking?: boolean }
 */
export async function GET(request: Request) {
  debugProcess('🚀 SAML AuthnRequest API started')
  
  try {
    // URL에서 RelayState 매개변수 추출
    const url = new URL(request.url)
    const relayState = url.searchParams.get('relayState')
    
    debugLog('RelayState parameter:', relayState)
    
    // 환경변수 검증
    const environment = validateSAMLEnvironment()
    
    debugProcess('SSO STEP 1: Create AuthnRequest')
    
    const startTime = Date.now()
    const loginUrl = await createAuthnRequest(relayState || undefined)
    const endTime = Date.now()
    
    debugSuccess('SAML AuthnRequest created successfully:', {
      url: loginUrl.substring(0, 100) + '...',
      urlLength: loginUrl.length,
      processingTime: `${endTime - startTime}ms`,
      mockMode: environment.SAML_MOCKING_IDP === 'true',
      timestamp: new Date().toISOString()
    })
    
    return NextResponse.json({
      loginUrl,
      success: true,
      isThisMocking: environment.SAML_MOCKING_IDP === 'true'
    })
  } catch (error) {
    debugError('Failed to create SAML AuthnRequest:', {
      error: error instanceof Error ? error.message : 'Unknown error',
      stack: error instanceof Error ? error.stack : undefined,
      timestamp: new Date().toISOString()
    })
    
    return NextResponse.json({
      error: 'Failed to create SAML AuthnRequest',
      details: error instanceof Error ? error.message : 'Unknown error',
      success: false
    }, { status: 500 })
  }
}