summaryrefslogtreecommitdiff
path: root/lib/saml/idp-metadata.ts
blob: a33ecad6bf8cedba55e933e935cb25b2702e739c (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
// SAML Identity Provider (IdP) 메타데이터 유틸리티

export interface IDPMetadata {
  entityId: string
  ssoUrl: string
  sloUrl?: string
  certificate: string
  nameIdFormat: string
  organization: string
  wantAuthnRequestsSigned: boolean
}

// IdP 메타데이터 가져오기 (환경변수 기반)
export function getIDPMetadata(): IDPMetadata {
  console.log('🔍 Loading IdP metadata from environment variables...')
  
  // 필수 환경변수 검증
  const entityId = process.env.SAML_IDP_ENTITY_ID
  const ssoUrl = process.env.SAML_IDP_SSO_URL
  const certificate = process.env.SAML_IDP_CERT
  
  if (!entityId || !ssoUrl || !certificate) {
    throw new Error('Required SAML IdP environment variables are missing: SAML_IDP_ENTITY_ID, SAML_IDP_SSO_URL, SAML_IDP_CERT')
  }

  const metadata: IDPMetadata = {
    entityId,
    ssoUrl,
    sloUrl: process.env.SAML_IDP_SLO_URL,
    certificate,
    nameIdFormat: process.env.SAML_IDP_NAME_ID_FORMAT || 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
    organization: process.env.SAML_IDP_ORGANIZATION || 'Unknown Organization',
    wantAuthnRequestsSigned: process.env.SAML_IDP_WANT_AUTHN_REQUESTS_SIGNED === 'true'
  }

  console.log('✅ IdP metadata loaded from environment variables:', {
    entityId,
    ssoUrl,
    sloUrl: metadata.sloUrl,
    organization: metadata.organization,
    wantAuthnRequestsSigned: metadata.wantAuthnRequestsSigned
  })

  return metadata
}

// 인증서 형식 정규화 (PEM 형식으로 변환)
export function normalizeCertificate(cert: string): string {
  // 이미 PEM 형식인 경우 그대로 반환
  if (cert.includes('-----BEGIN CERTIFICATE-----')) {
    return cert
  }
  
  // Base64 인증서를 PEM 형식으로 변환 (64자마다 줄바꿈)
  const cleanCert = cert.replace(/\s+/g, '')
  const formattedCert = cleanCert.match(/.{1,64}/g)?.join('\n') || cleanCert
  return `-----BEGIN CERTIFICATE-----\n${formattedCert}\n-----END CERTIFICATE-----`
}

// 특정 용도의 인증서 가져오기
export function getCertificateByUse(metadata: IDPMetadata, use: 'signing' | 'encryption'): string {
  const cert = metadata.certificates.find(c => c.use === use)
  return cert ? normalizeCertificate(cert.certificate) : ''
}

// 모든 인증서를 PEM 형식으로 변환
export function getAllCertificatesAsPEM(metadata: IDPMetadata): { use: string; pem: string }[] {
  return metadata.certificates.map(cert => ({
    use: cert.use,
    pem: normalizeCertificate(cert.certificate)
  }))
}

// 레거시 호환성을 위한 함수 - 첫 번째 인증서를 문자열로 반환
export function getFirstCertificateAsString(metadata: IDPMetadata): string {
  return metadata.certificates[0]?.certificate || ''
}

// SP 메타데이터 생성을 위한 헬퍼
export function getSPEntityId(): string {
  return process.env.SAML_SP_ENTITY_ID || `${process.env.NEXTAUTH_URL}/saml/metadata`
}

export function getSPCallbackUrl(): string {
  return `${process.env.NEXTAUTH_URL}/api/saml/callback`
}