From abd9f950bbd95b9ad713a26d3fd8a7e0282b7c51 Mon Sep 17 00:00:00 2001 From: joonhoekim <26rote@gmail.com> Date: Fri, 20 Jun 2025 11:47:15 +0000 Subject: (김준회) SAML 2.0 SSO (Knox Portal) 추가 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/saml/sp-metadata.ts | 82 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 lib/saml/sp-metadata.ts (limited to 'lib/saml/sp-metadata.ts') diff --git a/lib/saml/sp-metadata.ts b/lib/saml/sp-metadata.ts new file mode 100644 index 00000000..7f25f602 --- /dev/null +++ b/lib/saml/sp-metadata.ts @@ -0,0 +1,82 @@ +// SAML Service Provider (SP) 메타데이터 유틸리티 + +export interface SPAssertionConsumerService { + binding: string + location: string + index: number + isDefault?: boolean +} + +export interface SPMetadata { + entityId: string + // SPSSODescriptor 속성들 + protocolSupportEnumeration: string[] + authnRequestsSigned: boolean + wantAssertionsSigned: boolean + // 서비스 엔드포인트들 + assertionConsumerServices: SPAssertionConsumerService[] + // 편의를 위한 기본값들 + defaultACS: SPAssertionConsumerService + callbackUrl: string +} + +// SP 메타데이터 가져오기 (환경변수 기반) +export function getSPMetadata(): SPMetadata { + console.log('🔍 Loading SP metadata from environment variables...') + + // 필수 환경변수 검증 + const entityId = process.env.SAML_SP_ENTITY_ID + const callbackUrl = process.env.SAML_SP_CALLBACK_URL || `${process.env.NEXTAUTH_URL}/api/saml/callback` + + if (!entityId) { + throw new Error('Required SAML environment variable is missing: SAML_SP_ENTITY_ID') + } + + if (!callbackUrl) { + throw new Error('SAML_SP_CALLBACK_URL or NEXTAUTH_URL environment variable is required') + } + + // AssertionConsumerService 구성 + const assertionConsumerServices: SPAssertionConsumerService[] = [ + // 기본 HTTP-POST 바인딩 + { + binding: process.env.SAML_SP_ACS_BINDING_PRIMARY || 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', + location: callbackUrl, + index: 0, + isDefault: true + } + ] + + // 보조 HTTP-Redirect 바인딩 (선택사항) + const secondaryBinding = process.env.SAML_SP_ACS_BINDING_SECONDARY + if (secondaryBinding) { + assertionConsumerServices.push({ + binding: secondaryBinding, + location: callbackUrl, + index: 1, + isDefault: false + }) + } + + const metadata: SPMetadata = { + entityId, + protocolSupportEnumeration: [ + process.env.SAML_SP_PROTOCOL_SUPPORT || 'urn:oasis:names:tc:SAML:2.0:protocol' + ], + authnRequestsSigned: process.env.SAML_SP_AUTHN_REQUESTS_SIGNED === 'true', + wantAssertionsSigned: process.env.SAML_SP_WANT_ASSERTIONS_SIGNED === 'true', + assertionConsumerServices, + defaultACS: assertionConsumerServices[0], + callbackUrl + } + + console.log('✅ SP metadata loaded from environment variables:', { + entityId, + callbackUrl, + authnRequestsSigned: metadata.authnRequestsSigned, + wantAssertionsSigned: metadata.wantAssertionsSigned, + acsCount: assertionConsumerServices.length + }) + + return metadata +} \ No newline at end of file -- cgit v1.2.3