diff options
Diffstat (limited to 'lib/saml/idp-metadata.ts')
| -rw-r--r-- | lib/saml/idp-metadata.ts | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/lib/saml/idp-metadata.ts b/lib/saml/idp-metadata.ts new file mode 100644 index 00000000..a33ecad6 --- /dev/null +++ b/lib/saml/idp-metadata.ts @@ -0,0 +1,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` +}
\ No newline at end of file |
