ADFS Adapter 가이드

ADFS Adapter 가이드

Microsoft ADFS (ActiveDirectory Federation Service)는 AD계정을 기반으로 웹서비스에 대해 SAML/Oauth기반의 SSO(Single-Sign-On)을 지원하는 서비스입니다.

MS에서는 SSO 연계된 웹서비스에 대해, 3rd Party 솔루션을 활용한 MFA(복합인증)을 지원하는데,이를 위해 개발/설치되어야 하는 것이 ADFS Adapter입니다.

ADFS Adapter의 구현에는 크게 두가지 방식이 있습니다.

  • Server-to-Server Call 방식
  • WebClient 방식

이 중 WebClient방식의 경우, MFA서버 ↔ AD(FS) 間 방화벽 개통을 최소화하고, MFA Provider에서 제공하는 CX를 활용하기에 ADFS Adaptor 경량화가 가능한 장점이 있습니다.

참고
SingleID ADFS Adapter는 WebClient 방식으로 개발되었습니다.
주의
본 문서의 도식에서는 nonce 값을 LDAP에 저장 하는 설정을 가정하여 작성되었습니다. nonce값은 MFA 결과에 대한 검증을 위해 사용되며, LDAP대신 MFA서버에 저장되도록 설정 변경이 가능합니다. 자세한 내용은 ADFS Adaptor 설정관련 매뉴얼을 참고부탁드립니다.

Server-to-Server Call 방식

Server-to-Server Call
그림. Server-to-Server Call 방식

WebClient 방식

WebClient
그림. WebClient 방식

내부 동작

Adapter 내부 전체 흐름도

Adapter 내부 전체 흐름도
그림. Adapter 내부 전체 흐름도

Adapter 첫 실행시 흐름도

Adapter 첫 실행시 흐름도
그림. Adapter 첫 실행시 흐름도

MFA 수행 후의 흐름도 (MFA PASS인 경우)

MFA 수행 후의 흐름도 (MFA PASS인 경우)
그림. MFA 수행 후의 흐름도 (MFA PASS인 경우)

MFA 수행 후의 흐름도 (MFA PASS 못한 경우)

MFA 수행 후의 흐름도 (MFA PASS 못한 경우)
그림. MFA 수행 후의 흐름도 (MFA PASS 못한 경우)

시나리오별 동작

시나리오별 동작
그림. 시나리오별 동작

Case #1

  • Passcode 입력 화면에서 제한 시간을 넘겨서 Timeout 된 경우입니다.
  • Timeout이 되면 “코드 재전송” 버튼이 활성화되며, 이 버튼을 눌러서 Passcode 재시도 할 수 있습니다.

Case #2

  • 틀린 Passcode를 입력한 경우입니다.
  • 3번까지 Passcode 입력을 시도할 수 있습니다.

Case #3

  • Passcode 입력을 3번 틀린 경우입니다.
  • 1분간 Passcode 입력을 할 수 없습니다.

Case #4

  • 정상적인 MFA 프로세스입니다.

Case #5

  • MFA 선택 화면에서 Passcode 입력하지 않고 새로운 브라우저 탭을 추가하고, MFA 선택까지 진행한 경우입니다.
  • 이 후에 최초의 탭에서 MFA를 성공합니다.
  • 이 후에 새로운 탭에서 Timeout 된 경우입니다.

Case #6

  • MFA 선택 화면에서 Passcode 입력하지 않고 새로운 브라우저 탭을 추가하고, MFA 선택까지 진행한 경우입니다.
  • 이 후에 최초의 탭에서 MFA를 성공합니다.
  • 이 후에 새로운 탭에서 틀린 Passcode를 입력한 경우입니다.

Case #7

  • MFA 선택 화면에서 Passcode 입력하지 않고 새로운 브라우저 탭을 추가하고, MFA 선택까지 진행한 경우입니다.
  • 이 후에 최초의 탭에서 MFA를 성공합니다.
  • 이 후에 정상 Passcode를 입력한 경우입니다.+
  • 1st tab, 2nd tab 모두 passcode 입력대기 상태에서 1st 인증 후에 2nd 인증시도하면 2nd에서 아무런 반응 없음 (페이지 멈춤)
  • 1st tab passcode 입력대기, 2nd tab MFA 선택대기 상태에서 1st 인증 후에 2nd MFA 종류 선택하면 에러 발생, 어댑터 동작하기 전에 AD에서 에러 메시지 표시함

시나리오별 동작

Adapter 설치

적용 방법

사전 점검

사전 점검

위치점검 항목비고
ADFS서버MFA서버 접속 가능 여부 (그룹망, TCP 80/443)
  • 품질계: ops-sopenapi.iam.samsung.net(42.15.248.26)
  • 운영계: sopenapi.iam.samsung.net(42.15.248.28)
nonce를 LDAP에 저장하도록 설정한 경우, MFA서버 통신 불필요
.NET Framework 4.8 설치 여부
사용자PCMFA 서버 접속 가능 여부 (인터넷망, TCP 80/443)
  • 품질계: ops-sopenapi.singleid.samsung.net
  • 운영계: sopenapi.singleid.samsung.net
접속 불가 시 다음 3가지 점검
① 방화벽 점검
② 프록시 점검
③ 웹사이트 차단 점검
표. 개인정보 입력항목

Adapter 배포

주의
ADFS서버가 여러 대로 구성되어 있는 경우, 아래 7단계 중 1 ~ 4단계는 모든 서버에 공통적으로 적용해야 합니다.
  1. Adapter 관련 파일을 ADFS 서버에 업로드 시킴
위치 : [drvie]:\ADFSadapter\

ADFSadapter.dll : Adapter 파일
ADFSadatper.ini : 환경 설정 파일
replace_dll.ps1 : 이미 설치된 Adapter를 개선 버전으로 교체 시 사용하는 스크립트 파일
restart_adfs.ps1 : AD FS 서비스 재시작 스크립트 파일
Assembly_netstandard2.0 폴더 : Adapter 적용 전 사전 설치 dll 파일들
  1. 해당 폴더에 ADFS 서비스 계정의 전체 권한 부여
C:\ADFSadapter 폴더 우클릭 > 속성 > 보안 > ADFS 서비스 계정 추가 후 모든 권한 허용 선택
※ ADFS 서비스 계정은 services.msc 실행 > ADFS 서비스 실행 계정 "다음 사용자로 로그온" 으로 확인
  1. Registry 추가
Adapter 관련 이벤트를 Windows 이벤트 로그에 찍기 위한 Registry 생성

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog 아래에 키 및 값(2개) 생성
- 생성 키 : MFA_Adapter
- MFA_Adapter에 값 2개 생성
   . 이름 : AutoBackupLogFiles
   . 종류 : DWORD(32비트) 값(REG_DWORD)
   . 데이터 : 0

   . 이름 : MaxSize
   . 종류 : DWORD(32비트) 값(REG_DWORD)
   . 데이터 : 16진수 80000

MFA_Adapter 키 아래에 키 및 값(1개) 생성
- 생성 키 : AdapterDLL
- AdapterDLL에 값 1개 생성
  . 이름 : EventMessageFile
  . 종류 : 확장 가능한 문자열 값(REG_EXPAND_SZ)
  . 데이터 : C:\Windows\Microsoft.NET\Framework64\v4.0.30319\EventLogMessages.dll
  1. Adapter에 필요한 dll 사전 설치 C:\ADFSadapter 내 Assembly_netstandard2.0 폴더는 사전 설치가 필요한 라이브러리 모음 설치 작업은 다음을 참고한다. ADFS Adapter가 실행될 때 필요한 어셈블리가 로드될 수 있도록 ADFS 서버 내 전역어셈블리캐시에 dll을 설치한다.
**dll 설치**

#사전 작업
C:\ADFSadapter 폴더에 Assembly_netstandard2.0 폴더 압축을 풀어 복사해둔다.
#관리자 권한으로 Powershell 실행 후 수행 위치 이동
PS>cd C:\ADFSadapter

#dll 설치
PS>.\gacutil.exe /il .\Assembly_netstandard2.0\AssemblyList.txt
#dll 확인
PS>.\gacutil.exe /l
안내
Assembly_netstandard v2.0.zip 파일은 메일(singleid.scp@samsung.com)로 별도로 요청하시기 바랍니다.

설치 필요한 어셈블리 파일들을 Assembly_netstandard2.0 폴더에 저장해두었으며, 서버에 해당 파일을 복사한 후 오프라인 상태에서 설치 가능 Assembly_netstandard2.0 폴더 : Microsoft.IdentityModel.Tokens v7.2, System.IdentityModel.Tokens.Jwt v7.2 어셈블리 설치를 위한 dll 파일 (dependancy 파일 모두 포함)

설치 dll 리스트

셈블리명설치 버전패키지 버전
Microsoft.Bcl.AsyncInterfaces1.0.0.01.0.0
Microsoft.IdentityModel.Abstractions7.2.0.07.2.0
Microsoft.IdentityModel.JsonWebTokens7.2.0.07.2.0
Microsoft.IdentityModel.Logging7.2.0.07.2.0
Microsoft.IdentityModel.Tokens7.2.0.07.2.0
System.Buffers4.0.3.04.5.1
System.IdentityModel.Tokens.Jwt7.2.0.07.2.0
System.Memory4.0.1.14.5.3
System.Numerics.Vectors4.1.4.04.5.0
Microsoft.CSharp4.0.4.04.5.0
System.Runtime.CompilerServices.Unsafe4.0.4.14.5.3
System.Security.Cryptography.Cng4.3.0.05.0.0
System.Text.Encodings.Web4.0.5.14.7.2
System.Text.Json4.0.1.24.7.2
System.Threading.Tasks.Extensions4.2.0.14.5.4
표. 설치 dll 리스트

Adapter 배포

nuget 파일을 다운 받아 설치하였으며, nuget 패키지 버전과 서버에 설치되는 버전 표기가 다르니 주의하세요. .net framework 4.8을 기준으로 dll은 .net standard2.0(.net framework 4.8 지원) 규격으로 사용하세요

패키지 다운로드 : NuGet Gallery | Microsoft.IdentityModel.Tokens 7.2.0

  1. Adapter 적용 powershell 관리자 모드로 실행하여 아래 명령어 수행
#수행 위치 이동
PS>cd C:\ADFSadapter

#dll 등록
PS>./gacutil.exe /if ADFSadapter.dll

#dll 확인
PS>./gacutil.exe /l ADFSadapter
 전역 어셈블리 캐시에 다음 어셈블리가 들어 있습니다.
  ADFSadapter, Version=1.2.1.0, Culture=neutral, PublicKeyToken=0e0fe476002e81b3, processorArchitecture=MSIL
#ADFS에 인증 공급자로 등록
PS>$typename="ADFSadapter.AuthenticationAdapter, ADFSadapter, Version=1.2.1.0, Culture=neutral, PublicKeyToken=0e0fe476002e81b3, processorArchitecture=MSIL"
PS>Register-AdfsAuthenticationProvider -TypeName $typename -Name "ADFSadapter"
#ADFS에 인증 공급자 확인
PS>Get-AdfsAuthenticationProvider 
AdminName                          : ADFS MFA Adapter
AllowedForPrimaryExtranet          : False
AllowedForPrimaryIntranet          : False
AllowedForAdditionalAuthentication : True
AuthenticationMethods              : {http://schemas.microsoft.com/ws/2012/12/authmethod/otp}
Descriptions                       : {[1033, ADFS MFA Adapter], [1042, ADFS MFA Adapter]}
DisplayNames                       : {[1033, ADFS MFA Adapter], [1042, ADFS MFA Adapter]}
Name                               : ADFSadapter
IdentityClaims                     : {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn}
IsCustom                           : True
RequiresIdentity                   : True
#ADFS 서비스 재시작
PS>net stop adfssrv
PS>net start adfssrv

#수행 위치 이동
PS>cd C:\ADFSadapter
#dll 등록
PS>./gacutil.exe /if ADFSadapter.dll
#dll 확인
PS>./gacutil.exe /l ADFSadapter
 전역 어셈블리 캐시에 다음 어셈블리가 들어 있습니다.
  ADFSadapter, Version=1.2.1.0, Culture=neutral, PublicKeyToken=0e0fe476002e81b3, processorArchitecture=MSIL
#ADFS 서비스 재시작
PS>net stop adfssrv
PS>net start adfssrv
  1. ADFS의 다단계 인증 방법 설정 AD FS 관리 > 서비스 > 인증 방법 > 다단계 인증 방법 > 편집 클릭 후 생성한 mfa(ADFS MFA Adapter) 선택 후 적용 (복수선택 가능)

  2. 신뢰 당사자 트러스트에 mfa 정책 적용 AD FS 관리 > 신뢰 당사자 트러스트 > 적용할 신뢰 당사자 트러스트 선택 > 액세스 제어 정책 편집 > ‘모든 사용자를 허용하고 MFA 요구’ 선택 후 적용

Adapter 업그레이드 및 변경

해당 방법은 기존에 ADFS MFA Adapter 가 등록되어 있는 상태에서 해당 Adapter를 업그레이드/변경할 경우에 수행하는 Adapter 교체 작업입니다. 교체 작업 시 해당 스크립트만 수행하면 Adapter 변경 및 적용이 완료 됩니다.

#수행 위치 이동하여 변경된 Adapter.dll 파일 업로드
PS>cd C:\ADFSadapter

#Adapter 교체 수행

PS>./replace_dll.ps1

확인창 출력 시 예(Y) 혹은 모두 예(A) 클릭
 - 예(Y) 혹은 모두 예(A) 선택 : ADFS에서 기존 Adapter 제거 후 교체 작업 진행 (정상 절차)
 - 아니요(N) 혹은 모두 아니요(L) 선택 : Adapter 제거 안하고 다음 단계로 수행되어 오류 발생
 - 일시 중단(S) 선택: 해당 스크립트 중단
참고
※ 주서버와 보조서버에서 모두 수행. 보조 서버에서는 ADFS에 등록 시 오류 발생하나 dll 설치를 위해서 수행 필요

Adapter 설정

Adapter 환경설정 파일에 대한 설명입니다. ADFS Adapter 적용하기 전에 반드시 환경설정을 먼저 해야 합니다.

안내

adapter 설치위치 변경 사항

adapter 1.2.0.6부터 C 드라이브 이외의 다른 드라이브에 설치가 가능합니다.

기존 : C:/ADFSadapter 에만 설치 변경 : C to Z 드라이브의 root에 설치 예시: C:/ADFSadapter , D:/ADFSadapter , E:/ADFSadapter , …… , Z:/ADFSadapter

주의사항 : 단 1개의 드라이브에만 설치해야 하며, 만일 여러 개의 드라이브에 설치된 경우 C to Z 스캔하면서 가장 먼저 발견된 디렉토리를 사용함

아래의 예시는, adapter를 C:\ADFSadapter 디렉토리에 설치한 경우입니다.

C 이외의 다른 드라이브에 설치한 경우, 아래의 예시에서 드라이브명(drive letter)만 변경하면 됩니다.

예시: D:\ADFSadapter 에 설치한 경우 ini 경로 → D:\ADFSadapter\ADFSadapter.ini

파일명 및 경로

  • 파일명 → ADFSadapter.ini
  • 전체 경로 → C:\ADFSadapter\ADFSadapter.ini
  • 파일 인코딩 → 반드시 UTF-8 로 저장할 것 (그렇지 않으면 한글이 깨짐)

알아두어야 할 점

값을 표현할때 " 와 ’ 를 사용할 수 있으며 = 좌우에 빈칸을 입력해도 됨 Value 의 앞뒤에 있는 공백은 Trim 처리 됨 아래의 Value는 모두 동일함 예1) MAIN_TITLE=DWP MFA Adapter 예2) MAIN_TITLE = DWP MFA Adapter 예3) MAIN_TITLE = “DWP MFA Adapter” 예4) MAIN_TITLE = " DWP MFA Adapter "

섹션 이름들 중에 뒷부분에 -1033, -1042 가 붙는 것들은 locale 을 의미함 최소한 1033 은 반드시 있어야 합니다.

locale number : 1033 (en-us), 1042 (ko) locale section : MFA-1033, MFA-1042, TXT-1033, TXT-1042, MSG-1033, MSG-1042

ini 파일 구조 예시

# ADFS MFA Adapter 환경 설정
# 설치위치 변경 사항
#   - v1.2.0.6 이전 : C:\ADFSadapter\ADFSadapter.ini
#   - v1.2.0.6 부터 : C 이외의 다른 드라이브에 설치할 수 있음 (adapter 리소스 설치한 위치와 동일)
#     예시: C:\ADFSadapter\ADFSadapter.ini , D:\ADFSadapter\ADFSadapter.ini , E:\ADFSadapter\ADFSadapter.ini
# 주의 : DLL 파일명은 ADFSadapter.dll 이며, 기존의 Nexsign 연계한 MFAadapter.dll과는 다름


# 값을 표현할때 " 와 ' 를 사용할 수 있으며 = 좌우에 빈칸을 입력해도 됩니다
# Value 의 앞뒤에 있는 공백은 Trim 처리 됩니다.
# 아래의 Value는 모두 동일합니다.
# 예1) MAIN_TITLE=ADFS MFA Adapter
# 예2) MAIN_TITLE = ADFS MFA Adapter
# 예3) MAIN_TITLE = "ADFS MFA Adapter"
# 예4) MAIN_TITLE = "   ADFS MFA Adapter   "


# 섹션 이름들 중에 뒷부분에 -1033, -1042 가 붙는 것들은 locale 을 의미합니다
# 최소한 1033 은 반드시 있어야 합니다
# locale number : 1033 (en-us), 1042 (ko)
# locale section : MFA-1033, MFA-1042, TXT-1033, TXT-1042, MSG-1033, MSG-1042


# LOG_LEVEL (Windows 이벤트 로그에 기록하는 기준)
# 0 : Error
# 1 : Error + Warning
# 2 : Error + Warning + Information + Debug


[MAIN]
MAIN_MFA_TITLE="ADFS MFA Adapter"
MAIN_CLAIM1=http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod
MAIN_CLAIM2=http://schemas.microsoft.com/ws/2012/12/authmethod/otp


# MFA API 정보
# URL 끝부분에 "/" 붙이지 말 것
#MFA_API_URL="https://stg2-cloud.singleid.samsung.net/test/common-api/open/v1.1/mfa/request"
MFA_API_URL="https://stg1-cloud.singleid.samsung.net/test/common-api/open/v1.1/mfa/request"
CONSUMER_KEY="**************************************"
SECRET_KEY="**************************************"


# Donmain vs Consumer Key 리스트
# 도메인별로 Consumer Key가 다른 경우에는 리스트로 나열 (이런 경우, 위의 CONSUMER_KEY 값을 비울 것)
# Reqeust Token의 sys 값에 대입
# 형태 : DOMAIN_CONSUMER_KEY_##=domain;consumerKey
# 예시: DOMAIN_CONSUMER_KEY_01=aaa.com;**************************************
#     DOMAIN_CONSUMER_KEY_02=bbb.com;**************************************
# (주의) CONSUMER_KEY 값과 리스트 값이 모두 있다면, CONSUMER_KEY 값만 사용함
DOMAIN_CONSUMER_KEY_01=aaa.com;**************************************
DOMAIN_CONSUMER_KEY_02=bbb.com;**************************************

# Donmain vs Secret Key 리스트
# 도메인별로 Secret Key가 다른 경우에는 리스트로 나열 (이런 경우, 위의 SECRET_KEY 값을 비울 것)
# 형태 : DOMAIN_SECRET_KEY_##=domain;secretKey
# 예시: DOMAIN_SECRET_KEY_01=aaa.com;**************************************
#     DOMAIN_SECRET_KEY_02=bbb.com;**************************************
# (주의) SECRET_KEY 값과 리스트 값이 모두 있다면, SECRET_KEY 값만 사용함
DOMAIN_SECRET_KEY_01=aaa.com;**************************************
DOMAIN_SECRET_KEY_02=bbb.com;**************************************

# LDAP Search 결과에 따른, MFA 진행 여부
# 0 : LDAP Search를 하지 않음 (아래의 LDAP_SERVER, LDAP_USE_IDPW, ... 등의 정보 사용하지 않음. token에는 빈 값 대입)
# 1 : LDAP Search를 시도하지만 실패해도 관계없음 (서버 실패, 정보 없음 등이 발생하여도 MFA 진행함. token에는 빈 값 대입)
# 2 : LDAP Search가 성공 & 사용자 정보가 존재해야 함 (사용자 정보가 존재할 경우에만 진행함. 단, 결과 값이 빈 값이어도 진행함)
USE_LDAP_SEARCH=1


# LDAP 주소와 ID/PW
# LDAP_SERVER는 domain, ipv4, ipv6 등의 3가지 모두 가능하며, 앞부분에 대문자 "LDAP://" 을 붙여야 함 (반드시 대문자)
# 예시: LDAP://adpw5004.hw.dev , LDAP://70.2.180.218 , LDAP://fe80::644b:3c9f:c5ac:ce1c%10
# ID/PW를 사용하려면 LDAP_USE_IDPW 값을 1, 사용하지 않으려면 LDAP_USE_IDPW 값을 0 으로 설정
# SSL/TLS 사용하려면 LDAP_SSLTLS 값을 1, 사용하지 않으려면 LDAP_SSLTLS 값을 0 으로 설정 (단, LDAP_USE_IDPW=1 인 경우에만 해당)
LDAP_SERVER="LDAP://adpw5004.hw.dev"
LDAP_USE_IDPW=1
LDAP_SSLTLS=1
LDAP_ID="isadmin"
LDAP_PW="sds*****"


# DNS Lookup을 하여 LDAP 서버(LDAP_SERVER)의 IP 주소를 확인하고, IP 주소 기반으로 접속 여부
# LDAP_SERVER 값이 IP(ipv4, ipv6)로 설정되어 있어도 DNS Lookup을 수행하며, IP 그대로 리턴됨
# 만약, DNS Lookup을 실패하면, LDAP_SERVER 값 그대로 접속
# 0 : LDAP_SERVER 값 그대로 서버에 접속 (DNS lookup 하지 않음)
# 1 : DNS lookup으로 IP 주소를 확인하여 LDAP 서버에 접속 (DNS lookup 결과 리스트에서 첫번째 IP 사용)
# 2 : DNS lookup으로 IP 주소를 확인하고, LDAP_WHITE_IP_## 리스트에서 가장 먼저 해당되는 IP를 사용 (리스트에 없으면, LDAP_SERVER 사용)
# 3 : DNS lookup으로 IP 주소를 확인하고, LDAP_WHITE_IP_## 리스트에서 가장 먼저 해당되는 IP를 사용 (리스트에 없으면, LDAP 접속 안함)
LDAP_DNS_LOOKUP=1


# DNS Lookup 결과가 여러 개일때, 첫번째 IP 주소로 연결이 안되면 그 다음 IP 주소로 시도할지 여부
# 예시: lookup 결과가 4개 : 1차 IP 연결 실패 -> 2차 IP 연결 시도 & 싪패 -> 3차 IP 연결 시도 & 싪패 -> 4차 IP 연결 시도
LDAP_DNS_IF_FAIL_USE_NEXT=1


# DNS Lookup 결과와 비교하는 접속 허용된 LDAP 서버 IP 리스트 (LDAP_DNS_LOOKUP = 2 or 3 인 경우에만 해당)
# LDAP_WHITE_IP_## 형태이며, 01부터 99까지 순차적으로 기록
# DNS Lookup 결과와 리스트를 순차적으로 비교
# IPv4, IPv6 형태로 기록 (동일한 서버의 IPv4, IPv6가 있다면 리스트의 앞순위에 있는 IP가 적용됨)
# DNS Lookup 결과 순서와 White IP 리스트 순서가 다르다면 -> White IP 리스트 순서를 따름
LDAP_WHITE_IP_01="70.2.180.218"
LDAP_WHITE_IP_02="fe80::644b:3c9f:c5ac:ce1c%10"


# 사용자 정보를 암호화할지 여부 (예: mobile, email 등)
# 대상 : USERINFO_## 리스트
# 암호화 여부에 따라 API 서버에 전송하는 token의 claim 이름이 다름
# 0 : 암호화 하지 않음 -> token의 claim 이름이 plainMobile, plainEmail
# 1 : 암호화 -> token의 claim 이름이 mobile, email
USERINFO_ENCRYPT=0


# LDAP Search할 사용자 정보 attribute name과 JWT token에 사용할 claim name (2개 값을 구분하는 delimeter = ";")
# 형태: USERINFO_## = attribute;encryptedClaim;plainClaim
#   예시: LDAP에서 "mail" 속성을 읽어서, JWT에 "email" claim으로 사용된다면 -> "mail;email;plainEmail"
# key 명칭은 "USERINFO_##" 형태로 하고, 시작은 USERINFO_01
# key 갯수 : 0개 ~ 최대 99개 (0개인 경우, ini에 아무것도 적지 않으면 되며, USERINFO_00 이라고 적지 말 것)
# 주의사항) USERINFO_##에서 ## 에 해당되는 숫자는 반드시 01부터 시작하며, 여러 개인 경우 번호가 끊어지지 않아야 함
#           USERINFO_01, USERINFO_02, USERINFO_03 : OK (01, 02, 03 정보가 사용됨)
#           USERINFO_01, USERINFO_02, USERINFO_05 : 02까지 읽고, 끊어진 번호 이후는 사용하지 않음 (01, 02 정보가 사용됨)
USERINFO_01=mobile;mobile;plainMobile
USERINFO_02=mail;email;plainEmail


# MFA API 서버가 Callback 해줄때, 결과 Parameter에 사용되는 Key 이름
# 예시: https://adpw5004.hw.dev/adfs/ls?client-request-id=xxxxxx&pullStatus=0&jwtTokenResponse=yyyyyy
KEY_NAME_IN_RESPONSE="jwtTokenResponse"


# JWT Token의 exp에 적용될 더하기 값
# 형테 : 일시분초(dhms) 형태의 문자열 -> 1d=86400, 1h=3600, 1m=60 (dhms 가 전혀 없는 단순 숫자는 초로 판단함)
# 예시1 : 1d02h38m27s -> 95907 초
# 예시2 : 12345 -> 12345 초
TOKEN_EXP_TIME=1d


# API 호출할때 구성하는 token에 client claim을 추가할지 여부
# client : SAML인 경우 issuer, OIDC인 경우 client-id
# 0 : token에 client 포함시키지 않음
# 1 : token에 client 포함
TOKEN_CLAIM_CLIENT=0


# MFA nonce(guid, requset-id) 검증 방법
# 0 : 검증 안함
# 1 : adapter가 생성한 guid를 LDAP에 저장/비교하는 방식 (adapter가 검증)
#     -> 관련 설정 값 : CACHE_ATTRIBUTE, CACHE_DELIMETER, SKEW_SECONDS, CACHE_LIFE_TIME
# 2 : API 서버가 생성한 requeset-id를 adapter가 받아서 호출 URL에 사용하는 방식 (API 서버가 검증)
#     -> 관련 설정 값 : MFA_VERIFY_URL
MFA_VERIFY_TYPE=2


# MFA 결과검증 URL (서버 to 서버 통신) : URL 뒷부분에 API 서버로부터 받은 {request-id}를 덧붙여서 호출함
# adapter는 리턴 200 (OK) 인지 확인하여 MFA 결과 처리
# URL 끝부분에 "/" 붙이지 말 것
MFA_VERIFY_URL="https://stg1-cloud.iam.samsung.net/test/common-api/open/v1.1/mfa/request/status"


# MFA 결과검증할때 사용할 보안 프로토콜
# 선택 가능한 프로토콜 (대소문자 구분 없음) : TLS12, TLS13
# (주의) SSL3, TLS, TLS11 은 사용하지 않음
MFA_VERIFY_SECURE_PROTOCOL="TLS12"


# 사용자의 req guid 값을 저장할 LDAP attribute의 이름
# (주의) LDAP에 write 권한이 있어야 함
CACHE_ATTRIBUTE="otherPager"


# LDAP에 저장하는 req + 시간 정보를 조합할때 사용하는 delimeter -> "req;시간"
CACHE_DELIMETER=";"


# LDAP에 저장된 req의 시간과 JWT 수신시 시간의 차이 허용치 (초단위)
# MFA 선택화면 누를 때가 아니라, AD 로그인 직후의 시간이므로 (MFA 선택화면 보일때 이미 시간이 저장되었음)
# 사용자가 MFA 선택화면 누르고 Passcode 입력할 때까지의 시간이 아님
# 따라서, tight 하게 시간을 설정하면 안되며, 1시간 정도가 적당?? (MFA 선택을 1시간 고민하는 사람이 있나?)
SKEW_SECONDS=3600


# LDAP에 저장된 req의 수명 -> 다음 access시 시간 확인해서 이전의 오래된 것들 삭제
# 형태 : 일시분초(dhms) 형태의 문자열 -> 1d=86400, 1h=3600, 1m=60 (dhms 가 전혀 없는 단순 숫자는 초로 판단함)
# 예시1 : 1d02h38m27s -> 95907 초
# 예시2 : 12345 -> 12345 초
CACHE_LIFE_TIME=1d


# Adapter 기능을 ByPass 할 것인지 여부 (0=정상 사용, 283901=무력화, 그 외 값들=정상 사용)
# MFA 기능 문제로 급하게 adapter 기능의 무력화가 필요한 비상 상황에서 사용
# 평상시에는 절대로 수정하지 말 것 -> 평상시 값은 0
# 주의 : 무력화하려면 반드시 정확한 값을 설정해야 함 (0 이외의 숫자가 해당되는 것이 아니며 정확한 숫자 필요함. noise 우려)
BYPASS_ADAPTER=0


[API]
API_SYSTEMNAME=SingleID


[MSG-1033]
MSG_INTERNAL_ERROR="Internal error occurred. Contact administrator."


[MSG-1042]
MSG_INTERNAL_ERROR="Internal error occurred. Contact administrator."


[MANAGE]
LOG_LEVEL=2

설정 값 설명

  • 값 고정 : 하단 테이블의 “설정 값” 컬럼에 표시된 값을 ADFS 서버에 설치시에도 그대로 사용한다는 의미
  • 영문, 한국어 이외의 언어를 추가하고자 한다면, 2개 Section에 대해서는 추가가 가능함 → MSG-1033, MSG-1042
dssKey설정 값 (예시)값 고정설명
MAINMAIN_MFA_TITLEADFS MFA AdapterOHTML 페이지 타이틀 (MFA 기능에 영향 없음)
MAIN_CLAIM1http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethodO반드시 좌측 값을 그대로 적용할 것
MAIN_CLAIM2http://schemas.microsoft.com/ws/2012/12/authmethod/otpO반드시 좌측 값을 그대로 적용할 것
MFA_API_URLhttps://stg2-cloud.singleid.samsung.net/test/common-api/open/v1.1/mfa/requestSingleID MFA API 주소
tenant에 따라서 달라질 수 있으므로, 정확한 주소 값을 확인해야 함
CONSUMER_KEY4312a8b9-75c4-7897-89a7-89347f18943eSingleID 로부터 발급받은 Consumer Key
SECRET_KEYgQgkyLVO6FR8vJkLtlgBiupsRM/ilgrbEfoKWRnhALd=SingleID 로부터 발급받은 Secret Key
JWT Signautre 검증에 사용
외부 공개 절대 금지
DOMAIN_CONSUMER_KEY_014312a8b9-75c4-7897-89a7-89347f18943eDonmain vs Consumer Key 리스트
도메인별로 Consumer Key가 다른 경우에는 리스트로 나열 (이런 경우, 위의 CONSUMER_KEY 값을 비울 것)
형태 : DOMAIN_CONSUMER_KEY_##=domain;consumerKey
예시:
DOMAIN_CONSUMER_KEY_01=aaa.com;4312a8b9-75c4-7897-89a7-89347f18943e
DOMAIN_CONSUMER_KEY_02=bbb.com;96567780-2b12-23da-637c-9375a6502d5a
(주의) CONSUMER_KEY 값과 리스트 값이 모두 있다면, CONSUMER_KEY 값만 사용함
DOMAIN_CONSUMER_KEY_0296567780-2b12-23da-637c-9375a6502d5a
DOMAIN_CONSUMER_KEY_##367c89d5-88f7-978a-9739-8ed21748f36b
DOMAIN_SECRET_KEY_01gQgkyLVO6FR8vJkLtlgBiupsRM/ilgrbEfoKWRnhALd=Donmain vs Secret Key 리스트
도메인별로 Secret Key가 다른 경우에는 리스트로 나열 (이런 경우, 위의 SECRET_KEY 값을 비울 것)
형태 : DOMAIN_SECRET_KEY_##=domain;secretKey
예시:
DOMAIN_SECRET_KEY_01=aaa.com;gQgkyLVO6FR8vJkLtlgBiupsRM/ilgrbEfoKWRnhALd=
DOMAIN_SECRET_KEY_02=bbb.com;kgkWRnLygQhsRgrLVbtKlO6FiLdABupEgoMR8v/ilfJ=
(주의) SECRET_KEY 값과 리스트 값이 모두 있다면, SECRET_KEY 값만 사용함
DOMAIN_SECRET_KEY_02kgkWRnLygQhsRgrLVbtKlO6FiLdABupEgoMR8v/ilfJ=
DOMAIN_SECRET_KEY_##dABupkRnLygQhsrLgWVRbt8vRgkLilLKlO1FioMgfJE=
USE_LDAP_SEARCH0 or 1 or 2LDAP Search 결과에 따른, MFA 진행 여부
0 : LDAP Search를 하지 않음 (아래의 LDAP_SERVER, LDAP_USE_IDPW, … 등의 정보 사용하지 않음. token에는 빈 값 대입)
1 : LDAP Search를 시도하지만 실패해도 관계없음 (서버 실패, 정보 없음 등이 발생하여도 MFA 진행함. token에는 빈 값 대입)
2 : LDAP Search가 성공 & 사용자 정보가 존재해야 함 (사용자 정보가 존재할 경우에만 진행함. 단, 결과 값이 빈 값이어도 진행함)
LDAP_SERVERLDAP://adpw5004.hw.devAD 사용자 정보를 Query 할 수 있는 LDAP 주소
domain, ipv4, ipv6 등의 3가지 모두 가능하며, 앞부분에 “LDAP://” 을 붙여야 함
LDAP_USE_IDPW0 or 1LDAP 접속시 id/pw를 사용하는지 여부
adapter는 시스템 권한으로 동작하므로 id/pw 필요없이 LDAP 접속이 되는 것이 일반적이나, 그렇지 않은 경우도 존재함
id/pw 사용하지 않고 접속하도록 설정한 상태에서 이벤트 로그에 AD 접속 에러가 있다면, id/pw를 사용하여 접속하도록 설정 필요
이 값을 1로 설정하면, LDAP_ID, LDAP_PW 값을 반드시 설정하여야 함
LDAP_SSLTLS0 or 1LDAP 연결시 SSL/TLS를 사용할지 여부
일반적으로 사용하도록 설정
LDAP_IDLDAP 접속 idLDAP 접속 id (LDAP_USE_IDPW=1 인 경우)
LDAP_PWLDAP 접속 pwLDAP 접속 pw (LDAP_USE_IDPW=1 인 경우)
LDAP_DNS_LOOKUP0 or 1 or 2 or 3DNS Lookup을 하여 LDAP 서버(LDAP_SERVER)의 IP 주소를 확인하고, IP 주소 기반으로 접속 여부
0 : LDAP_SERVER 값 그대로 서버에 접속 (DNS lookup 하지 않음)
1 : DNS lookup으로 IP 주소를 확인하여 LDAP 서버에 접속 (DNS lookup 결과 리스트에서 첫번째 IP 사용)
2 : DNS lookup으로 IP 주소를 확인하고, LDAP_WHITE_IP_## 리스트에서 가장 먼저 해당되는 IP를 사용 (리스트에 없으면, LDAP_SERVER 사용)
3 : DNS lookup으로 IP 주소를 확인하고, LDAP_WHITE_IP_## 리스트에서 가장 먼저 해당되는 IP를 사용 (리스트에 없으면, LDAP 접속 안함)
LDAP_DNS_IF_FAIL_USE_NEXT0 or 1DNS Lookup 결과가 여러 개일때, 첫번째 IP 주소로 연결이 안되면 그 다음 IP 주소로 시도할지 여부
예시: lookup 결과가 4개 : 1차 IP 연결 실패 -> 2차 IP 연결 시도 & 실패 -> 3차 IP 연결 시도 & 실패 -> 4차 IP 연결 시도
LDAP_WHITE_IP_0170.2.180.218DNS Lookup 결과와 비교하는 접속 허용된 LDAP 서버 IP 리스트 (LDAP_DNS_LOOKUP = 2 or 3 인 경우에만 해당)
LDAP_WHITE_IP_## 형태이며, 01부터 99까지 순차적으로 기록
DNS Lookup 결과와 리스트를 순차적으로 비교
IPv4, IPv6 형태로 기록 (동일한 서버의 IPv4, IPv6가 있다면 리스트의 앞순위에 있는 IP가 적용됨)
DNS Lookup 결과 순서와 White IP 리스트 순서가 다르다면 → White IP 리스트 순서를 따름
LDAP_WHITE_IP_02fe80::644b:3c9f:c5ac:ce1c%10
LDAP_WHITE_IP_##A. : 01 ~ 99
White IP 주소 (IPv4 or IPv6)
USERINFO_ENCRYPT0 or 1사용자 정보를 암호화할지 여부 (예: mobile, email 등)
대상 : USERINFO_## 리스트
암호화 여부에 따라 API 서버에 전송하는 token의 claim 이름이 다름
0 : 암호화 하지 않음 -> token의 claim 이름이 plainMobile, plainEmail
1 : 암호화 -> token의 claim 이름이 mobile, email
USERINFO_01mobile;mobile;plainMobileOLDAP Search할 사용자 정보 attribute name과 JWT token에 사용할 claim name (3개 값을 구분하는 delimeter = “;”)
형태: USERINFO_## = attribute;encryptedClaim;plainClaim
예시: LDAP에서 “mail” 속성을 읽어서, JWT에 암호화된 값은 “email” claim으로 , 평문 값은 “plainEmail” claim으로 사용된다면 → “mail;email;plainEmail”
USERINFO_02mail;email;plainEmailO
USERINFO_##A. : 01 ~ 99
[LDAP attribute name];[encrypted token claim name];[plain token claim name]
KEY_NAME_IN_RESPONSEjwtTokenResponseOMFA API 서버가 Callback 해줄때, 결과 Parameter에 사용되는 Key 이름
예시: https://adpw5004.hw.dev/adfs/ls?client-request-id=xxxxxx&pullStatus=0&jwtTokenResponse=yyyyyy
TOKEN_EXP_TIME1dJWT Token의 exp에 적용될 더하기 값
일시분초(dhms) 형태의 문자열
1d=86400, 1h=3600, 1m=60
dhms 가 전혀 없는 단순 숫자는 초로 판단함
예시1 : 1d02h38m27s → 95907 초
예시2 : 12345 → 12345 초
TOKEN_CLAIM_CLIENT0 or 1API 호출할때 구성하는 token에 client claim을 추가할지 여부
client : SAML인 경우 issuer, OIDC인 경우 client-id
0 : token에 client 포함시키지 않음
1 : token에 client 포함
MFA_VERIFY_TYPE0 or 1 or 2MFA nonce(guid, requset-id) 검증 방법
0 : 검증 안함
1 : adapter가 생성한 guid를 LDAP에 저장/비교하는 방식 (adapter가 검증) → 관련 설정 값 : CACHE_ATTRIBUTE, CACHE_DELIMETER, SKEW_SECONDS, CACHE_LIFE_TIME
2 : API 서버가 생성한 requeset-id를 adapter가 받아서 호출 URL에 사용하는 방식 (API 서버가 검증) → 관련 설정 값 : MFA_VERIFY_URL
MFA_VERIFY_URLhttps://stg1-cloud.iam.samsung.net/test/common-api/open/v1.1/mfa/request/statusMFA 결과검증 URL (서버 to 서버 통신) : URL 뒷부분에 API 서버로부터 받은 {request-id}를 덧붙여서 호출함 → adapter는 리턴 200 (OK) 인지 확인하여 MFA 결과 처리
URL 끝부분에 “/” 붙이지 말 것
MFA_VERIFY_SECURE_PROTOCOLTLS12 or TLS13MFA 결과검증할때 사용할 보안 프로토콜
선택 가능한 프로토콜 (대소문자 구분 없음) : TLS12, TLS13
(주의) SSL3, TLS, TLS11 은 사용하지 않음
CACHE_ATTRIBUTEotherPagerO사용자의 req guid 값을 저장할 LDAP attribute의 이름
CACHE_DELIMETER“;”LDAP에 저장하는 req + 시간 정보를 조합할때 사용하는 delimeter -> “req;시간”
SKEW_SECONDS3600LDAP에 저장된 req의 시간과 JWT 수신시 시간의 차이 허용치 (초단위)
MFA 선택화면 누를 때가 아니라, AD 로그인 직후의 시간이므로 (MFA 선택화면 보일때 이미 시간이 저장되었음)
사용자가 MFA 선택화면 누르고 Passcode 입력할 때까지의 시간이 아님
따라서, tight 하게 시간을 설정하면 안되며, 1시간 정도가 적당?? (MFA 선택을 1시간 고민하는 사람이 있나?)
CACHE_LIFE_TIME1dLDAP에 저장된 req의 수명 -> 다음 access시 시간 확인해서 이전의 오래된 것들 삭제
일시분초(dhms) 형태의 문자열
1d=86400, 1h=3600, 1m=60
(dhms 가 전혀 없는 단순 숫자는 초로 판단함)
BYPASS_ADAPTER0 or 283901Adapter 기능을 ByPass 할 것인지 여부 (0=정상 사용, 283901=무력화, 그 외 값들=정상 사용)
MFA 기능 문제로 급하게 adapter 기능의 무력화가 필요한 비상 상황에서 사용
평상시에는 절대로 수정하지 말 것 -> 평상시 값은 0
주의 : 무력화하려면 반드시 정확한 값을 설정해야 함 (0 이외의 숫자가 해당되는 것이 아니며 정확한 숫자 필요함. noise 우려)
APIAPI_SYSTEMNAMESingleIDO(MFA 기능에 영향 없음)
MSG-1033MSG_INTERNAL_ERROR“Internal error occurred. Contact administrator.”인증중단, 오류발생 등으로 진행을 멈출때 사용자에게 보여주는 메시지 (영문)
MSG-1042MSG_INTERNAL_ERROR“Internal error occurred. Contact administrator.”인증중단, 오류발생 등으로 진행을 멈출때 사용자에게 보여주는 메시지 (한글)
한글 입력하면 에러 발생하니, 영문으로 입력할 것
MANAGELOG_LEVEL0 또는 1 또는 2윈도우 이벤트 로그에 기록하는 기준
0 = 에러만 기록
1 = 에러 + 경고만 기록
2 = 에러 + 경고 + 안내 등 모두 기록
표. 설정값 설명

INI 설정 방법

  1. LDAP Search 관련

    • LDAP 서버의 hostName으로 DNS Lookup 사용하고자 할 때
    • 여러개의 DNS Lookup 결과 중에서 첫번째 주소만 사용하고자 할 때
    • 여러개의 DNS Lookup 결과를 모두 순차적으로 접속 시도하고자 할 때
    • LDAP 서버 접속시 id/pw를 사용하고자 할 때
    • 허용된 LDAP 주소만 접속하고자 할 때 (White IP list)
    • LDAP에서 조회할 사용자 attribute 설정
  2. API 연결 관련

    • API 서버에 전송할 token에 포함되는 사용자 정보의 암호화 여부
    • MFA 무결성 검증 방법 : 어댑터가 검증
    • MFA 무결성 검증 방법 : API 서버가 검증
  3. 기타

    • 절대로 변경하면 안되는 옵션
    • SingleID 운영부서에게서 발급받아서 설정해야 하는 옵션
    • 설치 환경에 맞게 설정해야 하는 옵션
주의
본 페이지에서 사용된 consumer key, secret key는 sample data입니다. (fake value)

LDAP Search 관련

LDAP 서버의 hostName으로 DNS Lookup 사용하고자 할 때

USE_LDAP_SEARCH=1
LDAP_SERVER="LDAP://adpw5004.hw.dev"
LDAP_DNS_LOOKUP=1

LDAP 서버 주소의 앞부분은 반드시 대문자 “LDAP://” 이어야 합니다. 개발 서버에서 테스트시 소문자인 경우 접속이 안되는 것으로 확인되었습니다. DNS Lookup에 실패하면, LDAP_SERVER 값을 그대로 LDAP 접속 주소로 사용합니다.

여러개의 DNS Lookup 결과 중에서 첫번째 주소만 사용하고자 할 때

LDAP_DNS_LOOKUP=1
LDAP_DNS_IF_FAIL_USE_NEXT=0
DNS Lookup 결과가 다음과 같다고 하면,
  • IP1 = 10.10.10.10
  • IP2 = 10.10.10.20
  • IP3 = 10.10.10.30

LDAP_DNS_IF_FAIL_USE_NEXT=0 로 되어 있으므로, IP1 만 서버 접속을 시도하고 성공/실패 여부와 관계없이 중단합니다. 따라서, LDAP_DNS_IF_FAIL_USE_NEXT=0 으로 설정하는 것은 주의를 요합니다.

여러개의 DNS Lookup 결과를 모두 순차적으로 접속 시도하고자 할 때

LDAP_DNS_LOOKUP=1
LDAP_DNS_IF_FAIL_USE_NEXT=1

DNS Lookup 결과가 다음과 같다고 하면,

  • IP1 = 10.10.10.10
  • P2 = 10.10.10.20
  • IP3 = 10.10.10.30

LDAP_DNS_IF_FAIL_USE_NEXT=1 로 되어 있으므로, 성공할때까지 순차적으로 IP1 , IP2 , IP3 을 접속 시도합니다. 예를 들어, IP2 에 접속 성공했다면 IP3 은 접속 시도를 하지 않습니다.

LDAP 서버 접속시 id/pw를 사용하고자 할 때

LDAP_ID="******"
LDAP_PW="******"

MFA는 시스템 권한으로 동작하므로 id/pw가 필요하지 않을 수 있습니다. 만일, id/pw 없이 LDAP 연결이 안된다면 (서버 로그에서 연결 여부를 알 수 있음) id/pw를 사용하는 설정으로 해보시기 바랍니다.

허용된 LDAP 주소만 접속하고자 할 때 (White IP list)

LDAP_DNS_LOOKUP=2
또는
LDAP_DNS_LOOKUP=3

LDAP_WHITE_IP_01="70.2.180.218"
LDAP_WHITE_IP_02="fe80::644b:3c9f:c5ac:ce1c%10"

DNS Lookup 결과를 그대로 사용하지 않고, White IP 리스트와 비교를 하고 White IP 리스트에 속하는 주소만 사용하는 방식입니다. 예를 들어, DNS Lookup 결과는 다음과 같고,

  • IP1 = 10.10.10.10
  • IP2 = 10.10.10.20
  • IP3 = 10.10.10.30

White IP 리스트는 다음과 같다면,

  • WIP1 = 10.10.10.20
  • WIP2 = 10.10.10.40

실제로 사용하는 주소는 IP2 = WIP1 = 10.10.10.20 입니다.

순서는 White IP 리스트 순서를 따릅니다. 다음의 경우, 10.10.10.30 , 10.10.10.20 의 순서로 서버에 접속 시도를 합니다.

  • IP1 = 10.10.10.10
  • IP2 = 10.10.10.20
  • IP3 = 10.10.10.30
  • WIP1 = 10.10.10.30
  • WIP2 = 10.10.10.20

White IP 리스트에 속하는 것이 없다면,

  • LDAP_DNS_LOOKUP=2 → LDAP_SERVER 값을 그대로 LDAP 접속 주소로 사용합니다.
  • LDAP_DNS_LOOKUP=3 → LDAP 서버에 접속을 안합니다. (사용에 주의가 필요한 옵션)

LDAP에서 조회할 사용자 attribute 설정

USERINFO_01=mobile;mobile;plainMobile
USERINFO_02=mail;email;plainEmail
USERINFO_03=company;company;plainCompany
USERINFO_04=department;department;plainDepartment
USERINFO_05=displayname;displayname;plainDisplayname

MFA API 서버에 전송할 Request Token에 포함시킬 사용자 정보 claim입니다. ini에 설정한 리스트 갯수만큼 LDAP에서 조회하고, 결과를 token에 포함시켜서 MFA API 서버에 전송합니다. 설정 규칙은 아래 페이지의 테이블에서 “USERINFO_##” 설명을 참고하시기 바랍니다.

위의 sample처럼 설정하고 LDAP 조회 결과값이 아래와 같다면,

  • mobile = +82-10-1234-5678
  • mail = gd.hong@samsung.com
  • company = 값 없음
  • department = 값 없음
  • displayname = Hong Gil Dong

Request Token은 아래처럼 구성됩니다. 조회 결과가 빈 값이면, 빈 값 그대로 token에 포함합니다. (아래의 plainCompany, plainDepartment 처럼)

{
  "sys": "4312a8b9-75c4-7897-89a7-89347f18943e",
  "uid": "gd.hong",
  "displayUid": "gd.hong",
  "rtn": "https://adpw5004.hw.dev:443/adfs/ls?client-request-id=4b978185-59e1-4018-c800-0080020000f6&pullStatus=0",
  "nbf": 1716346465,
  "exp": 1716432865,
  "iat": 1716346465,
  "authType": "saml",
  "returnMethod": "get",
  "plainMobile": "+82-10-1234-5678",
  "plainEmail": "gd.hong@samsung.com",
  "plainCompany": "",
  "plainDepartment": "",
  "plainDisplayname": "Hong Gil Dong"
}

LDAP에서 조회하지 않으려면, 설정값을 비우거나 remark 처리하면 됩니다. 이런 경우, token에는 사용자 정보가 들어가지 않습니다.

USERINFO_01=
또는
#USERINFO_01=mobile;mobile;plainMobile

API 연결 관련

API 서버에 전송할 token에 포함되는 사용자 정보의 암호화 여부

USERINFO_ENCRYPT=0

어댑터 버전 1.2.0.8 기준으로, API 서버의 암호화 로직과 동일하게 구현되지 않아서 암호화 전송이 불가능한 상황입니다. 서버는 AES GCM 암호화를 하지만, 어댑터는 개발환경 특성상 AES GCM을 사용하지 못하기 때문입니다.

  • 대상 정보 : mobile, email

따라서, USERINFO_ENCRYPT=0 으로 사용합니다. 어댑터와 API 서버간에는 https 로 연결되어 중간자 탈취 문제는 없을 것으로 보입니다.

MFA 무결성 검증 방법 : 어댑터가 검증

MFA_VERIFY_TYPE=1
CACHE_ATTRIBUTE="otherPager"
CACHE_DELIMETER=";"
SKEW_SECONDS=3600
CACHE_LIFE_TIME=1d

이 옵션을 사용하기 위한 필수 조건

  • LDAP에 쓰기(write) 권한이 있어야 함 → 매주 중요 !

LDAP의 사용자 정보 중에서 otherPager 라는 attribute을 임시 저장공간처럼 이용하는 방식입니다. 어댑터는 세션 개념이 없어서 자체적으로 정보를 저장 또는 기억할 수 없기 때문입니다.

LDAP 서버는 LDAP Search의 주소와 동일합니다. 즉, LDAP SERVER, LDAP_DNS_LOOKUP 등의 옵션도 적용된다는 의미입니다.

위의 설정은 다음처럼 해석됩니다.

  • MFA_VERIFY_TYPE=1 : adapter가 생성한 guid를 LDAP에 저장/비교하는 방식 (adapter가 검증)
  • LDAP 사용자 정보의 “otherPager"라는 attribute을 사용
  • 저장되는 여러 개의 정보는 “;” 로 구분하여 string concat → 예시: “aaa;bbb;ccc”
  • LDAP에 저장된 req의 시간과 JWT 수신시 시간의 차이 허용치는 3600초
  • LDAP에 저장된 req의 수명은 1d (하루) → 다음 access시 시간 확인해서 이전의 오래된 것들 삭제

MFA 무결성 검증 방법 : API 서버가 검증

MFA_VERIFY_TYPE=2
MFA_VERIFY_URL="https://stg1-cloud.iam.samsung.net/test/common-api/open/v1.1/mfa/request/status"
MFA_VERIFY_SECURE_PROTOCOL="TLS12"

API 서버가 응답한 MFA 결과 jwt token을 어댑터가 수신하면 token의 정보 중에서 req 값을 이용하여 다시 API 서버에 되물어 보고 그 결과가 200 인지 확인하는 방식입니다.

위의 설정은 다음처럼 해석됩니다.

  • MFA_VERIFY_TYPE=2 : API 서버가 생성한 requeset-id를 adapter가 받아서 호출 URL에 사용하는 방식 (API 서버가 검증)
  • MFA_VERIFY_URL 주소로 다시 되물어 봄
  • 보안 프로토콜은 TLS 1.2 사용

기타

MAIN_CLAIM1=http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod
MAIN_CLAIM2=http://schemas.microsoft.com/ws/2012/12/authmethod/otp
KEY_NAME_IN_RESPONSE="jwtTokenResponse"
CACHE_ATTRIBUTE="otherPager"
CACHE_DELIMETER=";"
BYPASS_ADAPTER=0

최초 설치시 제공되는 INI 파일의 내용 그대로를 유지하여야 합니다. 임의로 변경시 어댑터가 전혀 동작하지 않을 수 있습니다. 일부 값들은 시스템 상황에 따라 변경이 필요할 수 있으나, 반드시 관게자/담당자의 의견 수렴이 선행되어야 합니다.

SingleID 운영부서에게서 발급받아서 설정해야 하는 옵션

MFA_API_URL="https://stg1-cloud.singleid.samsung.net/test/common-api/open/v1.1/mfa/request"
CONSUMER_KEY="4312a8b9-75c4-7897-89a7-89347f18943e"
SECRET_KEY="gQgkyLVO6FR8vJkLtlgBiupsRM/ilgrbEfoKWRnhALd="
MFA_VERIFY_URL="https://stg1-cloud.iam.samsung.net/test/common-api/open/v1.1/mfa/request/status"
MFA_VERIFY_SECURE_PROTOCOL="TLS12"

API 관련 주소, key, bearer 값들이며, SingleID 운영부서가 제공합니다. 보안 프로토콜(MFA_VERIFY_SECURE_PROTOCOL)의 일반적인 설정은 TLS 1.2 입니다.

설치 환경에 맞게 설정해야 하는 옵션

LDAP_SERVER="LDAP://adpw5004.hw.dev"
LDAP_ID="******"
LDAP_PW="******"
LDAP_WHITE_IP_01="70.2.180.218"
LDAP_WHITE_IP_02="fe80::644b:3c9f:c5ac:ce1c%10"

설치되는 환경 조사가 이루어 진 후에 결정되는 옵션들입니다.

INI 설정과 결과

  1. USERINFO_ENCRYPT
  2. USE_LDAP_SEARCH
  3. LDAP_DNS_LOOKUP
  4. LDAP_DNS_IF_FAIL_USE_NEXT
  5. LDAP_USE_IDPW
  6. MFA_VERIFY_TYPE
    주의
    본 페이지에서 사용된 consumer key, secret key는 sample data입니다. (fake value)

USERINFO_ENCRYPT

USERINFO_ENCRYPT=0

어댑터가 MFA API 서버에 전송하는 token에 포함되는 사용자 정보가 암호화인지 평문인지 여부를 설정합니다. (예를 들면, mobile, email) 어댑터 버전 v1.2.0.8 (‘24년 4월) 현재, AES/GCM/NoPadding을 사용할 수 없으므로 평문으로 설정합니다. 즉, USERINFO_ENCRYPT=0 으로 고정입니다. 후일, 어댑터가 AES/GCM/NoPadding을 지원할 수 있으면, 설정을 변경할 수 있습니다.

USE_LDAP_SEARCH

USE_LDAP_SEARCH=0

LDAP_SERVER=“LDAP://adpw5004.hw.dev” USE_LDAP_SEARCH가 0 이므로, LDAP_SERVER 값은 사용되지 않습니다. 즉, USE_LDAP_SEARCH가 0 이면, LDAP_SERVER를 빈 값으로 하거나 삭제해도 됩니다.

USE_LDAP_SEARCH=1

LDAP 검색이 실패한다면?

  • 사용자 정보를 빈 값 처리하여 다음 단계로 진행합니다.
  • 실패의 원인이 서버 연결 실패이든 정보 없음이든 관계없습니다.
USE_LDAP_SEARCH=2

LDAP 검색이 실패한다면?

  • 사용자에게 에러를 표시하며 진행을 중지합니다.
  • 서버 로그에는 아래와 같이 기록됩니다. (또는 유사한 내용)
  • “LDAP에서 사용자 정보를 가져올 수 없습니다.”

이 옵션은 매우 신중하게 사용해야 하며, 가급적 USE_LDAP_SEARCH=1 로 설정하시기 바랍니다. 사용자 정보가 없는 것에 대한 처리는 MFA API 측에 맡기는 것이 바람직할 것입니다. 어댑터는 이러한 상황에 대한 사용자 안내처리 및 기능이 미흡할 수 밖에 없기 때문입니다.

LDAP_DNS_LOOKUP

LDAP_SERVER="LDAP://adpw5004.hw.dev"
LDAP_DNS_LOOKUP=1
LDAP_WHITE_IP_01="10.10.10.10"
LDAP_WHITE_IP_02="10.10.10.30"

어댑터는 DNS lookup 결과를 메모리에 리스트 형태로 기억해둡니다. (순서가 있는 리스트) → LDAP 주소 리스트 LDAP 서버 이중화이고 각각의 IP가 아래와 같다고 가정합니다. (DNS에서 lookup이 되는 IP)

  • IP#1 : 10.10.10.10
  • IP#2 : 10.10.10.20

DNS lookup 결과는 IPv4, IPv6 모두 해당되므로, 아래처럼 결과가 나옵니다. (아래는 sample이며, 실제와 다름)

  • IP#1 = fe80::644b:3c9f:c5ac:ce1c%10
  • IP#2 = fe80::f03d:b045:8dc3:f5ed%3
  • IP#3 = 10.10.10.10
  • IP#4 = 10.10.10.20

이 상태에서 다음의 Case들을 생각해볼 수 있습니다.

Case 1) DNS Lookup 실패했다면

  • LDAP 주소 리스트의 갯수는 1개이며, LDAP_SERVER 값을 그대로 대입됩니다.
  • 즉, LDAP 주소 리스트의 1번째 값 = “LDAP://adpw5004.hw.dev”

Case 2) DNS Lookup 성공하고, White IP 리스트 설정 값이 있다면 (LDAP_WHITE_IP_##=“x.x.x.x”)

  • White IP 리스트의 순서대로 LDAP 주소 리스트가 만들어집니다.
  • 위의 sample의 경우, LDAP 주소 리스트의 값은 아래와 같습니다.
  • 1번째 값 = 10.10.10.10
  • 2번째 White IP 10.10.10.30 은 DNS Lookup 결과에 없기 때문에 LDAP 주소 리스트에 반영하지 않습니다.

Case 3) DNS Lookup 성공하고, White IP 리스트 설정 값이 없다면 (LDAP_WHITE_IP_##=”" 또는 LDAP_WHITE_IP_## 없음)

  • DNS Lookup 결과를 LDAP 주소 리스트에 반영합니다.
  • 위의 sample의 경우, LDAP 주소 리스트의 값은 아래와 같습니다.
  • 1번째 값 = fe80::644b:3c9f:c5ac:ce1c%10
  • 2번째 값 = fe80::f03d:b045:8dc3:f5ed%3
  • 3번째 값 = 10.10.10.10
  • 4번째 값 = 10.10.10.20

LDAP_DNS_IF_FAIL_USE_NEXT

LDAP_DNS_IF_FAIL_USE_NEXT=0

LDAP 주소 리스트가 아래와 같다고 가정합니다.

  • 1번째 값 = 10.10.10.10
  • 2번째 값 = 10.10.10.20

1번째 주소 10.10.10.10 으로 접속시도 후 실패하면 더 이상 진행하지 않습니다. LDAP 검색 결과(사용자 정보)는 빈 값으로 설정합니다.

LDAP_DNS_IF_FAIL_USE_NEXT=1

LDAP 주소 리스트가 아래와 같다고 가정합니다.

  • 1번째 값 = 10.10.10.10
  • 2번째 값 = 10.10.10.20

1번째 주소 10.10.10.10 으로 접속시도 후 실패하면 2번째 주소로 접속시도 합니다. 2번째 접속까지 실패하면, LDAP 검색 결과(사용자 정보)는 빈 값으로 설정합니다.

LDAP_USE_IDPW

LDAP_USE_IDPW=0
LDAP_ID="******"
LDAP_PW="******"

LDAP_USE_IDPW가 0 이면, LDAP_ID, LDAP_PW 값은 사용되지 않습니다. 즉, LDAP_USE_IDPW가 0 이면, LDAP_ID, LDAP_PW를 빈 값으로 하거나 삭제해도 됩니다.

LDAP_USE_IDPW=1
LDAP_ID=""
LDAP_PW=""

LDAP_USE_IDPW가 1 이면, LDAP_ID, LDAP_PW 값이 반드시 필요합니다. 따라서, 위의 sample처럼 LDAP_ID, LDAP_PW 값을 비워두거나 삭제하면, LDAP 서버에 접속이 되지 않습니다.

LDAP_USE_IDPW=1
LDAP_ID="******"
LDAP_PW="******"

LDAP 접속에 id/pw를 사용한다는 의미인데, 접속이 실패한다면 id/pw가 정확한지 확인해 봅니다. INI 파일은 plain text 이므로, id/pw가 노출될 우려가 있습니다. 따라서, 가급적 id/pw 사용하지 않아도 LDAP 접속이 되도록 서버 환경 구성이 필요합니다.

MFA_VERIFY_TYPE

MFA_VERIFY_TYPE=0

어댑터 관점에서의 MFA 결과 검증이란, 사용자의 MFA 수행은 MFA API를 통해서 하는 것인데, 그 결과를 어댑터가 재확인하는 것을 의미합니다. MFA_VERIFY_TYPE 값이 0 이면, MFA 결과 검증을 안한다는 의미입니다. 정상적인 운영상태에서는 0 으로 설정하지 않습니다.

MFA_VERIFY_TYPE=1
CACHE_ATTRIBUTE="otherPager"
CACHE_DELIMETER=";"

MFA 결과 검증을 어댑터가 직접 수행합니다. 이를 위해서는 LDAP 서버를 활용하며, LDAP write 권한이 필수입니다. CACHE_ATTRIBUTE 값은 변경 금지입니다.

MFA_VERIFY_TYPE=2
MFA_VERIFY_URL="https://stg1-cloud.iam.samsung.net/test/common-api/open/v1.1/mfa/request/status"
MFA_VERIFY_SECURE_PROTOCOL="TLS12"

MFA 결과 검증을 MFA API 서버에 의뢰합니다. LDAP write 권한이 없을 때의 대안입니다.

INI 설정 예시

예시 1

USE_LDAP_SEARCH=0
LDAP_SERVER="LDAP://adpw5004.hw.dev"
LDAP_DNS_LOOKUP=0
MFA_VERIFY_TYPE=1
CACHE_ATTRIBUTE="otherPager"
CACHE_DELIMETER=";"
  • LDAP search를 사용하지 않습니다.
  • API 서버에 전송하는 token에 포함되는 사용자 정보는 빈 문자열 값으로 설정됩니다. (예: mobile, email 등)
  • LDAP search를 사용하지 않는데도 LDAP_SERVER 정보가 있는 이유는 MFA_VERIFY_TYPE=1 이기 때문입니다.
  • LDAP 서버에 대한 DNS Lookup은 하지 않습니다.
  • 즉, LDAP_SERVER 값을 그대로 LDAP 주소로 사용합니다.
  • MFA 결과 검증을 어댑터가 직접 하는데, 이 때 LDAP 서버를 활용합니다. 그러므로, LDAP 서버 주소 값이 있어야 합니다.
  • 위의 설정은, LDAP 서버내 사용자 정보의 “otherPager"라는 attribute에 어댑터가 생성한 nonce를 저장하고, MFA 완료시 꺼내서 비교한다는 의미입니다.

예시 2

USE_LDAP_SEARCH=1
LDAP_SERVER="LDAP://adpw5004.hw.dev"
LDAP_USE_IDPW=0
LDAP_SSLTLS=1
LDAP_DNS_LOOKUP=0
MFA_VERIFY_TYPE=1
CACHE_ATTRIBUTE="otherPager"
CACHE_DELIMETER=";"
  • LDAP search를 사용합니다.
  • 사용자 정보를 LDAP에서 조회합니다. (예: mobile, email 등)
  • LDAP 접속에 실패하거나 조회 결과가 없을 경우, 사용자 정보는 빈 문자열 값으로 설정됩니다.
  • LDAP 접속시 id/pw를 사용하지 않습니다.
  • id/pw를 입력하지 않아도 LDAP에 접속이 되는 경우에 해당됩니다.
  • LDAP 연결시 SSL/TLS를 사용하여 보안성을 높입니다.
  • LDAP 서버에 대한 DNS Lookup은 하지 않습니다.
  • 즉, LDAP_SERVER 값을 그대로 LDAP 주소로 사용합니다.
    • MFA 결과 검증을 어댑터가 직접 하는데, 이 때 LDAP 서버를 활용합니다. 그러므로, LDAP 서버 주소 값이 있어야 합니다.
  • 위의 설정은, LDAP 서버내 사용자 정보의 “otherPager"라는 attribute에 어댑터가 생성한 nonce를 저장하고, MFA 완료시 꺼내서 비교한다는 의미입니다.

예시 3

USE_LDAP_SEARCH=1
LDAP_SERVER="LDAP://adpw5004.hw.dev"
LDAP_USE_IDPW=0
LDAP_DNS_LOOKUP=0
MFA_VERIFY_TYPE=2
MFA_VERIFY_URL="https://stg1-cloud.iam.samsung.net/test/common-api/open/v1.1/mfa/request/status"
MFA_VERIFY_SECURE_PROTOCOL="TLS12"
  • LDAP search를 사용합니다.
  • 사용자 정보를 LDAP에서 조회합니다. (예: mobile, email 등)
  • LDAP 접속에 실패하거나 조회 결과가 없을 경우, 사용자 정보는 빈 문자열 값으로 설정됩니다.
  • LDAP 접속시 id/pw를 사용하지 않습니다.
  • id/pw를 입력하지 않아도 LDAP에 접속이 되는 경우에 해당됩니다.
  • LDAP 서버에 대한 DNS Lookup은 하지 않습니다.
  • 즉, LDAP_SERVER 값을 그대로 LDAP 주소로 사용합니다.
  • MFA 결과 검증을 API 서버가 하며, 보안 프로토콜은 TLS 1.2를 사용합니다.
  • API 서버로부터 받은 MFA 결과 response token에 포함된 “req” 값을 추출하고, 이것을 결과검증 URL 뒷부분에 붙입니다.
  • → MFA_VERIFY_URL + “/” + req
  • → 예시: req가 “xxxxxx” 일때,
  • https://stg1-cloud.iam.samsung.net/test/common-api/open/v1.1/mfa/request/status/xxxxxx

예시 4

USE_LDAP_SEARCH=1
LDAP_SERVER="LDAP://adpw5004.hw.dev"
LDAP_USE_IDPW=1
LDAP_SSLTLS=1
LDAP_ID="******"
LDAP_PW="******"
LDAP_DNS_LOOKUP=1
LDAP_DNS_IF_FAIL_USE_NEXT=0
MFA_VERIFY_TYPE=1
CACHE_ATTRIBUTE="otherPager"
CACHE_DELIMETER=";"
  • LDAP search를 사용합니다.
  • 사용자 정보를 LDAP에서 조회합니다. (예: mobile, email 등)
  • LDAP 접속에 실패하거나 조회 결과가 없을 경우, 사용자 정보는 빈 문자열 값으로 설정됩니다.
  • LDAP 접속시 id/pw를 사용합니다. *이 계정은 write 권한을 가지고 있어야 합니다.
  • LDAP 연결시 SSL/TLS를 사용하여 보안성을 높입니다.
  • LDAP 서버에 대하여 DNS Lookup을 사용합니다.
  • DNS Lookup 결과를 LDAP 주소 테이블에 그대로 대입합니다.
  • DNS Lookup에 실패하면, LDAP 주소 테이블에는 LDAP_SERVER 값 1개만 기록됩니다.
  • LDAP 주소 테이블에서 제일 처음의 것 1개만 접속 시도합니다.
  • 실패하더라도 다음 순서의 서버로 접속을 시도하지 않습니다.
  • MFA 결과 검증을 어댑터가 직접 하는데, 이 때 LDAP 서버를 활용합니다. 그러므로, LDAP 서버 주소 값이 있어야 합니다.
  • 위의 설정은, LDAP 서버내 사용자 정보의 “otherPager"라는 attribute에 어댑터가 생성한 nonce를 저장하고, MFA 완료시 꺼내서 비교한다는 의미입니다.

예시 5

USE_LDAP_SEARCH=1
LDAP_SERVER="LDAP://adpw5004.hw.dev"
LDAP_USE_IDPW=1
LDAP_SSLTLS=1
LDAP_ID="******"
LDAP_PW="******"
LDAP_DNS_LOOKUP=1
LDAP_DNS_IF_FAIL_USE_NEXT=0
LDAP_WHITE_IP_01=""
LDAP_WHITE_IP_02=""
MFA_VERIFY_TYPE=1
CACHE_ATTRIBUTE="otherPager"
CACHE_DELIMETER=";"
  • 예시 4와 동일한 설정입니다.
  • LDAP_WHITE_IP_##이 존재하지만 빈 값이므로, 존재하지 않는 것과 동일하다는 의미입니다.

예시 6

USE_LDAP_SEARCH=1
LDAP_SERVER="LDAP://adpw5004.hw.dev"
LDAP_USE_IDPW=1
LDAP_SSLTLS=1
LDAP_ID="******"
LDAP_PW="******"
LDAP_DNS_LOOKUP=1
LDAP_DNS_IF_FAIL_USE_NEXT=1
LDAP_WHITE_IP_01="70.2.180.218"
LDAP_WHITE_IP_02="fe80::644b:3c9f:c5ac:ce1c%10"
MFA_VERIFY_TYPE=2
MFA_VERIFY_URL="https://stg1-cloud.iam.samsung.net/test/common-api/open/v1.1/mfa/request/status"
MFA_VERIFY_SECURE_PROTOCOL="TLS12"
  • LDAP search를 사용합니다.
  • 사용자 정보를 LDAP에서 조회합니다. (예: mobile, email 등)
  • LDAP 접속에 실패하거나 조회 결과가 없을 경우, 사용자 정보는 빈 문자열 값으로 설정됩니다.
  • LDAP 접속시 id/pw를 사용합니다.
  • 이 계정은 write 권한을 가지고 있어야 합니다.
  • LDAP 연결시 SSL/TLS를 사용하여 보안성을 높입니다.
  • LDAP 서버에 대하여 DNS Lookup을 사용합니다.
  • DNS Lookup을 한 결과와 White IP 리스트를 대조하여, White IP 리스트의 순서대로 LDAP 주소 테이블을 만듭니다.
  • DNS Lookup을 성공하여도 White IP 리스트에 존재하지 않는다면, LDAP 주소 테이블에는 LDAP_SERVER 값 1개만 기록됩니다.
  • DNS Lookup에 실패하면, LDAP 주소 테이블에는 LDAP_SERVER 값 1개만 기록됩니다.
  • LDAP 주소 테이블을 처음부터 차례대로 접속 시도를 하며,
  • 실패하면 다음 순서의 서버로 접속을 시도하는 방식입니다.
  • MFA 결과 검증을 API 서버가 하며, 보안 프로토콜은 TLS 1.2를 사용합니다.
  • API 서버로부터 받은 MFA 결과 response token에 포함된 “req” 값을 추출하고, 이것을 결과검증 URL 뒷부분에 붙입니다.
  • → MFA_VERIFY_URL + “/” + req
  • → 예시: req가 “xxxxxx” 일때, https://stg1-cloud.iam.samsung.net/test/common-api/open/v1.1/mfa/request/status/xxxxxx

ADFS Adapter 관리

서비스 확인

설정 확인

  • AD FS 관리 > 서비스 > 인증 방법 > 다단계 인증 방법 > ADFS MFA Adapter 설정됨 확인
설정 확인
설정 확인
테스트 SP
테스트 SP

서버 이벤트 로그

Adapter 실행 과정의 로그는 윈도우 이벤트 로그 영역에 기록합니다.

ADFSadapter.ini 설정에서 LOG_LEVEL 값을 조정하면, 에러, 경고, 일반로그를 선택적으로 기록할 수 있습니다.

ADFSadapter.ini 에서 LOG_LEVEL 설정

값 설정기록하는 로그
LOG_LEVEL=0에러 기록
LOG_LEVEL=1에러, 경고 기록
LOG_LEVEL=2에러, 경고, 일반 메시지 모두 기록

윈도우 이벤트 로그 위치

  • 컴퓨터 관리(로컬) > 시스템 도구 > 이벤트 뷰어 > 응용 프로그램 및 서비스 로그 > MFA_Adapter
  • 계정별 로그의 시작에는 MFA 버전과 계정명이 표시되어 있음 → 로그 분석/추적에 참고
  • 운영시에는, “오류” 또는 “경고” 로 표시된 부분을 집중적으로 모니터링
    이벤트 뷰어

윈도우 이벤트 로그 설명 및 조치방법

[#0000] Success
Err.Success
에러가 아니고, 단순한 로그입니다.
불필요한 로그이며, 이 로그가 보인다면 개발자에게 해당 로그 삭제하라고 하시면 됩니다.

[#0001] Invalid Arguments
Err.InvalidArguments
에러 : adapter 프로그램 내부의 함수 호출할 때, 함수 인자(argument) 누락이 있다는 뜻입니다.
조치 : 심각한 에러이며, 개발자에게 즉시 전달하여 신속히 조치되도록 합니다.
참고
별다른 증상없이 adapter가 동작할 수도 있으나, 심각한 에러 잠재성이 있으므로 방치하면 안됩니다.

[#1000] identityClaim 에서 계정정보(account)를 추출할 수 없습니다.
Err.IdentityClaimHasNoAccount
에러 : adapter 실행 초기에 AD 서버로부터 현재 사용자의 정보를 받는데, account 정보를 찾을 수 없습니다.
조치 : AD 서버 상태를 확인해봅니다.
참고
LDAP에서 Query 하는 것이 아니라, ADFS 내부적으로 처리되는 정보 흐름으로서, 이 상황이 발생하면 adapter가 정상 동작할 수 없는 환경이라고 보면 됩니다.

[#1001] INI 파일을 load 할 수 없습니다.
Err.FailToLoadIni
에러 : 서버에서 MFA 환경설정 INI 파일을 읽을 수 없습니다.
조치 : 서버에 다음의 경로에 파일이 있는지 확인
C:\ ADFSadapter \ ADFSadapter.ini
참고
만일, 파일이 있다면, 파일 속성 또는 권한 확인합니다.

[#1002] HTML 파일들을 load 할 수 없습니다.
Err.FailToLoadHtml
에러 : 서버에서 HTML 파일을 읽을 수 없습니다.
조치 : 서버에 다음의 경로에 파일이 있는지 확인합니다.
C:\ ADFSadapter \ Html_*.txt
참고
만일, 파일이 있다면, 파일 속성 또는 권한 확인합니다. 1개라도 없으면 에러 발생힙니다. 어떤 것이 누락되었는지는 서버 이벤트 로그에서 알 수 있습니다.

[#1003] LDAP에서 사용자 정보를 가져올 수 없습니다.
Err.FailToLdapSearch
에러 : LDAP 서버에 Query를 헀으나, AD 사용자 정보를 가져오지 못했습니다.
조치 : AD 서버 상태를 확인해봅니다.
참고
Token 구성에 mobile, email 정보가 필요한데, 이 정보들을 가져올때 실패한 것입니다. 사용자 정보가 존재한다면, mobile, email이 빈 값이어도 에러로 처리하지 않습니다. 그래서, 본 에러가 발생한 것은 LDAP Query 자체가 안된다고 보면 됩니다.

[#1004] BeginAuthentication 함수의 request에 URL 정보가 없습니다.
Err.NoURLInRequest
에러 : Adapter 실행 초기에 실행되는 BeginAuthentication 함수의 인자 request에 URL 정보가 없습니다.
조치 : SingleID MFA API 서버가 정상적으로 response를 보내는지 확인합니다.
참고
URL 정보가 없으면, SingleID MFA API 서버가 GET 방식으로 전송한 response를 사용할 수 없습니다.

[#1005] JWT token 생성을 할 수 없습니다.
Err.FailToMakeJwtToken
에러 : GenerateRequestToken 함수가 token 생성에 실패했습니다.
조치 : 정확한 원인은 서버 이벤트 로그에서 확인 가능하며, 개발자에게 원인 분석을 요청합니다.

[#1006] ADFSadapter 디렉토리 또는 INI 파일을 찾을 수 없습니다. C to Z 드라이브 중의 한 곳에 [drive]:/ADFSadapter/ADFSadapter.ini 파일이 존재해야 합니다.
Err.CannotFindDirOrIni
에러 : adapter 버전 1.2.0.6 부터 adapter 설치 위치가 C 드라이브 고정이 아닌 C to Z 드라이브 중의 한 곳에 설치할 수 있으며, adapter는 C to Z 드라이브 스캔을 통해서 설치된 위치를 알아냅니다. [drive]:/ADFSadapter/ADFSadapter.ini 파일이 존재해야 합니다.
조치 : 서버에 adapter 설치가 제대로 되었는지, 디렉토리명과 파일명이 정확한지 확인합니다. 드라이브 억세스가 막혀있는지 확인합니다.

[#2000] TryEndAuthentication()에 계정정보(account)가 없습니다.
Err.TryEndHasNoAccount
에러 : TryEndAuthentication 단계로 넘어왔으나, 계정 정보를 알 수 없습니다. (adpater 자체 에러)
조치 : 개발자에게 신속히 상황 전달 및 원인 분석을 요청합니다.
참고
이러한 경우는 절대 발생할 수 없으며, 발생해서도 안됩니다.

[#2001] Step 정보가 없습니다.
Err.NoStepInfo
에러 : MFA 진행 단계(step) 정보가 없습니다. (adpater 자체 에러)
조치 : 개발자에게 신속히 상황 전달 및 원인 분석을 요청합니다.
참고
이러한 경우는 절대 발생할 수 없으며, 발생해서도 안됩니다.

[#2002] 잘못된 Step 정보입니다.
Err.InvalidStepInfo
에러 : MFA 진행 단계(step) 정보가 잘 못 되었습니다. (adpater 자체 에러)
조치 : 개발자에게 신속히 상황 전달 및 원인 분석을 요청합니다.
참고
이러한 경우는 절대 발생할 수 없으며, 발생해서도 안됩니다.

[#3000] HTML 문자열을 가져옵니다.
Err.SucceedInGetHtml
에러가 아니고, 단순한 로그입니다. 서버의 Html_.txt 파일을 읽은 내용을 보여줍니다. Html_.txt 파일 내용 수정 후에 adpater가 파일 내용을 제대로 읽었는지 확인할 때 도움이 됩니다.

[#3001] HTML을 가져올 수 없습니다.
Err.FailToGetHtml
에러 : 서버의 Html_*.txt 파일을 읽지 못한 것입니다.
조치 : 파일이 존재하는지, Read 권한이 있는지, Lock 걸려있는지 등을 확인해봅니다.

[#4000] Html 파일이 존재하지 않습니다.
Err.HtmlFileNotFound
에러 : 서버의 Html_*.txt 파일을 읽지 못한 것입니다.
조치 : 파일이 존재하는지, 확인해봅니다.

[#4001] Html 파일이 존재하나, 파일 내용이 없습니다.
Err.HtmlFileIsEmpty
에러 : 서버의 Html_*.txt 파일을 읽지 못한 것입니다.
조치 : 파일 Read 권한이 있는지, Lock 걸려있는지 등을 확인해봅니다.

[#4002] HtmlPrefix 리스트에 없는 step 입니다.
Err.StepNotInHtmlPrefixList
에러 : adapter 내부에는 처리 step 별로 정의해 둔 keyword 리스트가 있는데, 그 리스트에 없는 keyword가 발견되었다는 뜻입니다.
조치 : 개발자에게 신속히 상황 전달 및 원인 분석을 요청합니다.
참고
이러한 경우는 절대 발생할 수 없으며, 발생해서도 안됩니다.

[#4003] HtmlPrefix 리스트에서 prefix 값이 비어 있습니다.
Err.EmptyPrefixInHtmlPrefixList
에러 : adapter 내부에는 처리 step 별로 정의해 둔 keyword 리스트가 있는데, 그 리스트에 아무런 내용이 없다는 뜻입니다.
조치 : 개발자에게 신속히 상황 전달 및 원인 분석을 요청합니다.
참고
이러한 경우는 절대 발생할 수 없으며, 발생해서도 안됩니다.

[#5000] ini 파일을 읽을 수 없습니다.
Err.FailToReadIniFile
에러 : INI 파일을 읽을 수 없습니다.
조치 : 서버에 다음의 경로에 파일이 있는지 확인
C:\ ADFSadapter \ ADFSadapter.ini
참고
만일, 파일이 있다면, 파일 속성 또는 권한 확인합니다.

[#5001] 시스템명칭(API_SYSTEMNAME)이 ini 에 없습니다.
Err.NoSystemNameInIni
에러 : INI 파일에 "API_SYSTEMNAME" 설정 값이 없습니다.
조치 : INI 전체적으로 누락된 것이 없는지, INI 가 구버전의 것인지 등을 확인힙니다.

[#5002] claim1(MAIN_CLAIM1)이 ini 에 없습니다.
Err.NoClaim1InIni
에러 : INI 파일에 "MAIN_CLAIM1" 설정 값이 없습니다.
조치 : INI 전체적으로 누락된 것이 없는지, INI 가 구버전의 것인지 등을 확인힙니다.

[#5003] claim2(MAIN_CLAIM2)가 ini 에 없습니다.
Err.NoClaim2InIni
에러 : INI 파일에 "MAIN_CLAIM2" 설정 값이 없습니다.
조치 : INI 전체적으로 누락된 것이 없는지, INI 가 구버전의 것인지 등을 확인힙니다.

[#5004] ini 파일이 존재하지 않습니다.
Err.IniFileNotFound
에러 : 서버에서 MFA 환경설정 INI 파일을 찾을 수 없습니다.
조치 : 서버에 다음의 경로에 파일이 있는지 확인
C:\ ADFSadapter \ ADFSadapter.ini

[#5005] ini 리스트에 AddToList() 실패했습니다.
Err.FailToAddIniList
에러 : adapter 내부 에러입니다.
조치 : 개발자에게 신속히 상황 전달 및 원인 분석을 요청합니다.
참고
이러한 경우는 절대 발생할 수 없으며, 발생해서도 안됩니다.

[#5006] ini 파일에서 읽어온 key, value가 아무것도 없습니다.
Err.NoKeyValueInIni
에러 : INI 파일을 읽었으나, key, value 조합으로 설정된 것이 전혀 없습니다.
조치 : INI 파일 내용을 확인힙니다.

[#5007] LDAP 서버 정보가 ini 에 없습니다. (LDAP_SERVER)
Err.NoLdapServerValueInIni
에러 : INI 파일에 "LDAP_SERVER" 설정 값이 없습니다.
조치 : INI 전체적으로 누락된 것이 없는지, INI 가 구버전의 것인지 등을 확인힙니다.

[#5008] MFA API URL이 ini 에 없습니다. (MFA_API_URL)
Err.NoMfaApiUrlValueInIni
에러 : INI 파일에 "MFA_API_URL" 설정 값이 없습니다.
조치 : INI 전체적으로 누락된 것이 없는지, INI 가 구버전의 것인지 등을 확인힙니다.

[#5009] Consumer Key 값이 ini 에 없습니다. (CONSUMER_KEY)
Err.NoConsumerKeyValueInIni
에러 : INI 파일에 "CONSUMER_KEY" 설정 값이 없습니다.
조치 : INI 전체적으로 누락된 것이 없는지, INI 가 구버전의 것인지 등을 확인힙니다.

[#5010] Secret Key 값이 ini 에 없습니다. (SECRET_KEY)
Err.NoSecretKeyValueInIni
에러 : INI 파일에 "SECRET_KEY" 설정 값이 없습니다.
조치 : INI 전체적으로 누락된 것이 없는지, INI 가 구버전의 것인지 등을 확인힙니다.

[#5011] Cache Attribute 값이 ini 에 없습니다. (CACHE_ATTRIBUTE)
Err.NoCacheAttributeValueInIni
에러 : INI 파일에 "CACHE_ATTRIBUTE" 설정 값이 없습니다.
조치 : INI 전체적으로 누락된 것이 없는지, INI 가 구버전의 것인지 등을 확인힙니다.

[#5012] Cache Delimeter 값이 ini 에 없습니다. (CACHE_DELIMETER)
Err.NoCacheDelimeterValueInIni
에러 : INI 파일에 "CACHE_DELIMETER" 설정 값이 없습니다.
조치 : INI 전체적으로 누락된 것이 없는지, INI 가 구버전의 것인지 등을 확인힙니다.

[#5013] Skew Seconds 값이 ini 에 없습니다. (SKEW_SECONDS)
Err.NoSkewSecondsValueInIni
에러 : INI 파일에 "SKEW_SECONDS" 설정 값이 없습니다.
조치 : INI 전체적으로 누락된 것이 없는지, INI 가 구버전의 것인지 등을 확인힙니다.

[#5014] Token expiration time 값이 ini 에 없습니다. (TOKEN_EXP_TIME)
Err.NoTokenExpTimeInIni
에러 : INI 파일에 "TOKEN_EXP_TIME" 설정 값이 없습니다.
조치 : INI 전체적으로 누락된 것이 없는지, INI 가 구버전의 것인지 등을 확인힙니다.

[#5015] Cache life time 값이 ini 에 없습니다. (CACHE_LIFE_TIME)
Err.NoCacheLifeTimeInIni
에러 : INI 파일에 "CACHE_LIFE_TIME" 설정 값이 없습니다.
조치 : INI 전체적으로 누락된 것이 없는지, INI 가 구버전의 것인지 등을 확인힙니다.

[#5016] 사용자 정보 claim 리스트가 ini 에 없습니다. (USERINFO_##)
Err.NoUserinfoListInIni
reserved (예약된 에러 코드이며, 향후 사용 예정)

[#5017] LDAP 연결시 id/pw 사용하도록 설정되어 있으나(LDAP_USE_IDPW=1), LDAP id 또는 pw가 ini 에 없습니다. (LDAP_ID, LDAP_PW)
Err.NoLdapIdPwInIni
에러 : LDAP 접속시 id/pw 사용하도록 설정되어 있으나, INI 파일에 LDAP_ID, LDAP_PW 설정 값이 없습니다.
조치 : INI 전체적으로 누락된 것이 없는지, INI 가 구버전의 것인지 등을 확인힙니다.

[#6000] AD(LDAP)에서 사용자 정보를 검색하는 과정에 Exception이 발생했습니다.
Err.ExceptionInAD
에러 : LDAP 서버에 Query를 헀으나, 그 과정 중에 Exception이 발생했습니다.
조치 : INI에 설정한 AD 서버 주소가 정확한지 확인해봅니다. 그리고, AD 서버 상태를 확인해봅니다.
참고
이벤트 로그에 있는 자세한 Exception 내용을 개발자에게 전달합니다.

[#6001] AD(LDAP)에서 사용자 정보를 찾을 수 없습니다.
Err.CannotFindUserInAD
에러 : LDAP 서버에 Query를 헀으나, AD 사용자 정보를 가져오지 못했습니다.
조치 : AD 서버 상태를 확인해봅니다.
참고
Token 구성에 mobile, email 정보가 필요한데, 이 정보들을 가져올때 실패한 것입니다. 사용자 정보가 존재한다면, mobile, email이 빈 값이어도 에러로 처리하지 않습니다. 그래서, 본 에러가 발생한 것은 LDAP Query 자체가 안된다고 보면 됩니다

사용자 에러 메시지

MFA 진행 과정에 에러가 발생하면, 사용자 PC 화면에 에러 메시지를 표시합니다. 에러 메시지는 “Internal error occurred. Contact administrator.” 로 고정되어 있으며, 다음 라인에 에러코드가 함께 표시됩니다.

Internal error occurred. Contact administrator.
ErrorCode : 0001

아래는 에러코드에 대한 원인과 조치방법에 대한 설명입니다.
※ 사용자 에러 메시지 이외의 서버 내부처리 과정의 이벤트 로그 참고

ErrorCode : 0001
* Err.IdentityClaimHasNoAccount
* 함수 호출시 인자(arguments)가 잘 못 되었음
* 사용자에게 보여주는 에러는 아님
+ → 혹시 보인다면, 개발자에게 문의
+ → 이 시점의 서버 이벤트 로그를 봐야 함

ErrorCode : 1000
* Err.IdentityClaimHasNoAccount
* "identityClaim 에서 계정정보(account)를 추출할 수 없습니다."
* adapter 실행 초기에 AD 서버로부터 현재 사용자의 정보를 받는데, account 정보를 찾을 수 없음
* LDAP에서 Query 하는 것이 아니라, ADFS 내부적으로 처리되는 정보 흐름으로서,
+ 이 상황이 발생하면 adapter가 정상 동작할 수 없는 환경이라고 보면 됨
* AD 서버 상태를 먼저 확인해 볼 것

ErrorCode : 1001
* Err.FailToLoadIni
* 서버에서 MFA 환경설정 INI 파일을 읽을 수 없음
* 서버에 다음의 경로에 파일이 있는지 확인
+ C:\ ADFSadapter \ ADFSadapter.ini
* 만일, 파일이 있다면, 파일 속성 또는 권한 확인

ErrorCode : 1002
* Err.FailToLoadHtml
* 서버에서 HTML 파일을 읽을 수 없음
* 서버에 다음의 경로에 파일이 있는지 확인
+ C:\ ADFSadapter \ Html_*.txt
* 만일, 파일이 있다면, 파일 속성 또는 권한 확인
* 1개라도 없으면 에러 발생함 → 어떤 것이 누락되었는지는 서버 이벤트 로그에서 알 수 있음

ErrorCode : 1003
* Err.FailToLdapSearch
* "LDAP에서 사용자 정보를 가져올 수 없습니다."
* LDAP 서버에 Query를 헀으나, AD 사용자 정보를 가져오지 못함
* Token 구성에 mobile, email 정보가 필요한데, 이 정보들을 가져올때 실패하였음
* mobile, email이 빈 값이어도 에러로 처리하지 않음
* 그래서, 본 에러가 발생한 것은 LDAP Query 자체가 안된다고 보면 됨

ErrorCode : 1004
* Err.NoURLInRequest
* "BeginAuthentication 함수의 request에 URL 정보가 없습니다."
* Adapter 실행 초기에 실행되는 BeginAuthentication 함수의 인자 request에 URL 정보가 없음
* URL 정보가 없으면, SingleID MFA API 서버가 GET 방식으로 전송한 response를 사용할 수 없음
* SingleID MFA API 서버가 정상적으로 response를 보내는지 확인 필요

ErrorCode : 1005
* Err.FailToMakeJwtToken
* "JWT token 생성을 할 수 없습니다."
* GenerateRequestToken 함수가 token 생성에 실패하였음
* 정확한 원인은 서버 이벤트 로그에서 확인

ErrorCode : 1006
* Err.CannotFindDirOrIni
* "JWT token 생성을 할 수 없습니다."
* ADFSadapter 디렉토리 또는 INI 파일을 찾을 수 없음
* adapter 버전 1.2.0.6 부터 adapter 설치 위치가 C 드라이브 고정이 아닌 C to Z 드라이브 중의 한 곳에 설치할 수 있으며,
+ adapter는 C to Z 드라이브 스캔을 통해서 설치된 위치를 알아냄
* [drive]:/ADFSadapter/ADFSadapter.ini 파일이 존재해야 함
* 서버에 adapter 설치가 제대로 되었는지, 디렉토리명과 파일명이 정확한지 확인
* 드라이브 억세스가 막혀있는지 확인

ErrorCode : 2000
* Err.TryEndHasNoAccount
* "TryEndAuthentication()에 계정정보(account)가 없습니다."
* TryEndAuthentication 단계로 넘어왔으나, 계정 정보를 알 수 없음
* 이러한 경우는 절대 발생할 수 없음 (발생하였다면, 개발자에게 문의)

ErrorCode : 2001
* Err.NoStepInfo
* MFA 진행 단계(step) 정보가 없음
* 상세 정보와 원인은 서버의 이벤트 로그를 확인할 것

ErrorCode : 2002
* Err.InvalidStepInfo
* MFA 진행 단계(step) 정보가 잘 못 되었음
* 상세 정보와 원인은 서버의 이벤트 로그를 확인할 것

ADFS 로그인 페이지 수정

onload.js 편집

배경

MFA를 여러 개 설정한 경우, 사용자는 아래와 같은 선택 화면을 보게 됩니다. 화면을 처음 보는 상황에서는(MFA를 아직 완료하지 않음), 이 화면에서 선택이 필요합니다.

ADFS 로그인 페이지 수정
ADFS 로그인 페이지 수정

문제점은, MFA를 거친 후에 선택 화면이 다시 표시된다는 것이며, 사용자가 선택하는 행위를 다시 해줘야 합니다. 이는 사용자 불편 사항이 되며, 두번째 선택에 다른 MFA를 선택하면 원치않은 결과가 나올 것입니다.

MFA가 완료된 후에 위의 선택 화면이 나올때, 자동으로 넘어가는 기능이 필요합니다. (auto submit) 이를 위해서, ADFS에 이미 존재하는 onload.js 파일의 내용을 편집하는 것입니다. Multi MFA가 아닌 경우에는 onload.js 파일 편집이 필요없습니다.

파일 경로

AD 서버의 아래 경로에 존재합니다.

  • 디렉토리 = C:/default_WebTheme/script
  • 파일명 = onload.js

파일 편집

파일 내용의 끝부분에 아래의 스크립트를 추가합니다.

주의
아래 예시의 Script Text를 복사 붙여넣기로 사용하면 안됩니다. 다국어 메시지가 아래 Text에서는 정상적으로 입력이 안되어 있습니다. 정상적인 Script Text가 포함된 파일을 별도로 준비하여야 합니다. onload.js 는 UTF-8로 저장되어야 합니다.
// ------------------------------------------ SingleID MFA : begin
function singleidMfa() {
    var authOptions = document.getElementById('authOptions')
    if (authOptions) {
        var noticeflag = document.getElementById('mfaGreeting');
        var url = document.location.href;
        var isToken = url.indexOf('jwtTokenResponse');
        if (noticeflag && isToken < 1) {
            var browserLang = navigator.language || navigator.userLanguage;
            // 다국어 처리
            // 한국어
            if (lang == 'ko-KR' || lang == 'ko') {
                document.getElementById('footerPlaceholder').innerHTML="<h3 style='font-weight: bold;'><br/> <br/> ※ 신규 복합인증솔루션 테스트 중 (13:00~15:00) <br/> &nbsp;&nbsp;&nbsp;'My Authentication Provider' 메뉴를 이용해주세요. </h3>";
            }
            // 중국어
            else if (lang == "zh" || lang.indexOf("zh-") > -1) {
                document.getElementById('footerPlaceholder').innerHTML="<h3 style='font-weight: bold;'><br/> <br/> ※ 正在??新的?合??解?方案 (13:00~15:00) <br/> &nbsp;&nbsp;&nbsp; ?登? 'My Authentication Provider' 菜?。 </h3>";
            }
            // 베트남어
            else if (lang == "vi") {
                document.getElementById('footerPlaceholder').innerHTML="<h3 style='font-weight: bold;'><br/> <br/> ※ đang ki?m tra gi?i phap xac th?c k?t h?p m?i (13:00~15:00) <br/> &nbsp;&nbsp;&nbsp; Xin vui long đ?ng nh?p vao trinh đ?n 'My Authentication Provider'. </h3>";
            }
            // 스페인어
            else if (lang == "es" || lang.indexOf("es-") > -1) {
                document.getElementById('footerPlaceholder').innerHTML="<h3 style='font-weight: bold;'><br/> <br/> ※ Prueba de una nueva solucion de autenticacion compleja (13:00~15:00) <br/> &nbsp;&nbsp;&nbsp; Inicie sesion en el menu 'My Authentication Provider'. </h3>";
            }
            // 영어
            else {
                document.getElementById('footerPlaceholder').innerHTML="<h3 style='font-weight: bold;'><br/> <br/> ※ Testing a new MFA solution (13:00~15:00) <br/> &nbsp;&nbsp;&nbsp; Please use 'My Authentication Provider' menu. </h3>";
            }
        }
        var opt = document.getElementById('optionSelection');
        if (opt && isToken > 0) {
            opt.value = 'ADFSadapter';
            document.forms['options'].submit();
        }
    }
}
window.addEventListener('load', function () {
    singleidMfa();
});
// ------------------------------------------ SingleID MFA : end

스크립트의 기능

  • 페이지의 컨트롤 중에 authOptions 가 있는 경우에 해당됩니다.
  • 페이지 load가 모두 완료된 이후에 동작하는 방식입니다. (그 전에 실행되면 에러가 발생하기 때문)
  • window.addEventListener 를 이용해서 load 이벤트에 추가 (window.onload 이벤트와 동일)
  • Case 1 : 컨트롤 중에 mfaGreeting 이 있고, URL에 jwtTokenResponse 가 없는 경우 브라우저 언어 설정에 맞추어 사용자 안내 메시지 출력 (다국어)
  • Case 2 : 컨트롤 중에 optionSelection 이 있고, URL에 jwtTokenResponse 가 있는 경우 optionSelection 에 ADFSadapter를 할당하고, options form을 강제로 submit 처리

스크립트 추가시 주의 사항

  • 기존 스크립트에 영향을 주지 않고 관리가 용이하도록, 스크립트의 마지막 부분에 넣는 것이 안전합니다.

onload.js 적용

onload.js 파일을 수정 반영하여 ADFS Sign-in Page customization 가능

주의
악성스크립트로 오탐 가능한 명령어가 포함되어있어, 실제 입력하셔야 하는 명령어와 다르게 표기된 명령어가 있습니다. -ON-LOADScriptPath 는 실제로 다음의 명령어이니 혼선 없으시길 바랍니다.

적용 방법

현황 확인

PS> Get-AdfsWebConfig ## 적용된(활성화 상태인) WebTheme 확인 PS> Get-AdfsWebTheme ## 생성된 WebTheme 리스트 확인

테마 적용

테마 적용 방법 1) default 테마에서 새로 만들기

PS> New-AdfsWebTheme -Name "custom_stg" -SourceName default  ## 새로운 WebTheme 생성
PS> Set-AdfsWebTheme -TargetName "custom_stg" -Illustration @{Path="C:\adfs_Login_dev\illustration\image_0624\8.jpg"} -Logo @{Path="C:\adfs_Login_dev\images\logo.png"} -StyleSheet @{Path="C:\adfs_Login_dev\css\style.css"} -ON-LOADScriptPath "C:\adfs_Login_dev\script\ON-LOAD_new.js"  ## custom 한 js 파일 적용

테마 적용 방법 2) 전자 테마에서 업데이트 하기

PS> New-AdfsWebTheme -Name "custom_stg" -SourceName [전자테마]  ## 새로운 WebTheme 생성
PS > Set-AdfsWebTheme -TargetName "custom_stg" -OnLoadScriptPath "C:\adfs_Login_dev\script\onload_stg.js"  ## custom 한 js 파일 적용
Onload.js
그림. 테마 적용

※ 테마 적용 방법 1), 2) 방법 서버 명령어 캡쳐본. Confluence 정리 시 OnLoad 명령어가 자동 변경되어 캡처본 첨부

PS> Set-AdfsWebConfig -ActiveThemeName "custom_stg"  ## 생성된 WebTheme 활성화

기존 테마 복구

PS> Set-AdfsWebConfig -ActiveThemeName "default" ## 기존 WebTheme 활성화
참고

하나의 WebTheme 에는 custom js 파일 하나만 적용 가능 MS에도 문의하였으나, 공식적으로 한 개의 onload.js 파일만 적용 가능하며, 추가적으로 제시한 방법은 적용 안됨

“the ON-LOAD.js is an integrated part of the HTML (the last script in the body) which always executes when the ADFS Page is loaded
There can be only one named ON-LOAD.JS per Web theme.
 
What is possible though is that additional ('external') scripts can be loaded as part of the actual ON-LOAD.js execution

let’s say in a specific part of your ON-LOAD.JS you want to load a bootstap.js which implements additional functionality
you would firstly import that additional JS to the webpage as AdditionalFileResource //it should not be named ON-LOAD.js

eg
Set-AdfsWebTheme -TargetName custom -AdditionalFileResource @{Uri='/adfs/portal/script/bootstrap.js';path="c:\theme\script\bootstrap.js"}

then you implement a loading functionality in the ON-LOAD.js which dynamically loads your additional script as needed”

참고 문서
http://www.javascriptkit.com/javatutors/loadjavascriptcss.shtml
https://www.codeproject.com/Articles/5310336/Dynamically-Loading-a-JavaScript-File


즉, 공식 문서에 기재한 대로 한개의 ADFS 테마 페이지에 한개의 ON-LOAD.JS 파일만 적용 가능합니다. 하지만 같은 페이지에 AdditionalFileResource로 다른 이름인 bootstap.js 파일을 추가적으로 적용할 수 있음을 제시했습니다.
참고

WebTheme 설정 시 추가 옵션 적용 가능

  • 옵션을 통해서 illustration, logo, stylesheet 등을 적용 할 수 있음
PS> Set-AdfsWebTheme -TargetName "custom_stg" -Illustration @{Path="C:\adfs_Login_dev\illustration\image_0624\8.jpg"} -Logo @{Path="C:\adfs_Login_dev\images\logo.png"}
       -StyleSheet @{Path="C:\adfs_Login_dev\css\style.css"} -OnLoadScriptPath "C:\adfs_Login_dev\script\onload_stg.js" 

참고 문서
https://learn.microsoft.com/en-us/powershell/module/adfs/set-adfswebtheme?view=windowsserver2022-ps

Adapter 표시이름 변경

다수의 Adapter를 적용하여 사용자가 선택하는 경우, Adapter의 표시이름을 설정하여 사용자(브라우저)에게 보여 줄 수 있음 기본적으로는 Adapter를 등록할 때 사용하는 이름(Name)이 표시됨

  1. 적용 전
    • Adapter를 등록할 때 사용한 이름으로 사용자(브라우저)에게 표시
  2. 적용 후
    • Adapter의 표시이름으로 사용자(브라우저)에게 표시
    • 언어별 표시이름을 다르게 설정할 수 있음
안내

테스트 시 언어 설정은 한국어, 영어, 글로벌 3가지로 적용

  1. 브라우저의 언어(chrome://settings/languages, edge://settings/languages) 에 따라, Adapter의 표시이름이 변경
  2. 브라우저의 언어에 영어(미국), 영어(영국) 등 en-으로 시작하는 언어는 모두 영어 설정이 적용. 한국어, 영어가 아닌 언어를 선택할 경우 글로벌 설정이 적용
  3. 설정 방법
    • ADFSadapter(신규 Adapter명)의 표시 이름 설정
    • ko(한국어), en(영어), 미설정(global) 3가지 로케일로 설정
    Set-AdfsAuthenticationProviderWebContent -Name "ADFSadapter" -Locale ko -DisplayName "신규 ADFS 플러그인(ko)" -Description "신규 ADFS 플러그인 설명(ko)"
    Set-AdfsAuthenticationProviderWebContent -Name "ADFSadapter" -locale en -DisplayName "New ADFS Plugin (en)" -Description "New ADFS Plugin Description (en)"
    Set-AdfsAuthenticationProviderWebContent -Name "ADFSadapter" -DisplayName "New ADFS Plugin(global)" -Description "New ADFS Plugin Description(global)"
    
    • MyAuthenticationProvider(기존 Adapter명)의 표시 이름 설정
    • ko(한국어), en(영어), 미설정(global) 3가지 로케일로 설정
    Set-AdfsAuthenticationProviderWebContent -Name "MyAuthenticationProvider" -locale "ko" -DisplayName "기존 ADFS 플러그인(ko)" -Description "기존 ADFS 플러그인 설명 (ko)"
    Set-AdfsAuthenticationProviderWebContent -Name "MyAuthenticationProvider" -locale "en" -DisplayName "ADFS Plugin (en)" -Description "ADFS Plugin Description (en)"
    Set-AdfsAuthenticationProviderWebContent -Name "MyAuthenticationProvider"  -DisplayName "ADFS Plugin (global)" -Description "ADFS Plugin Description (global)"
    

Locale ID는 다음 참고[MS-OE376]: 별도 문의

ADFS Adapter 관련 Tips

Adapter 등록 및 동작 순서 요약

  • Adapter DLL → GAC 영역에 등록 → ADFS에 등록 → ADFS 관리에서 다단계 인증방법에 체크 → AD 인증의 MFA 요구시 Adapter 동작

Adapter 관리에 필요한 도구 (gacutil.exe)

  • Adapter DLL을 AD FS 서버의 GAC 영역에 등록/삭제하는 도구
참고

GAC란 무엇인가?

Global Assembly Cache 의 약자이며, .NET Assembly를 머신 전체에서 공유하여 사용하기 위한 특별한 Cache GAC는 Windows 디렉토리 밑에 assembly라는 디렉토리에 있음

  • GAC에 설치되는 Assembly는 Strongly-named assembly 이어야만 함
  • DLL은 이름과 함께 Version, Culture, public key를 모두 포함해야 함
  • DLL이 GAC에 설치되면, 실행시 우선 순위를 갖게 됨
  • 동일한 DLL명을 사용해도 여러 Version 이 공존할 수 있음

GAC에 Adapter 등록/삭제 (gacutil.exe 활용)

일반적으로 cmd에서 사용하지만, 작업편의상 PowerShell 에서 사용함 (단, .\gacutil.exe 형태로 사용해야 함)

  • GAC에 등록
PS C:\ADFSadapter> .\gacutil.exe  /if  ADFSadapter.dll
  • GAC에서 삭제 → C:\ADFSadapter\ADFSadapter.dll 파일이 삭제되지는 않음
PS C:\ADFSadapter> .\gacutil.exe  /u  ADFSadapter
  • GAC에 등록되었는지 확인
PS C:\ADFSadapter> .\gacutil.exe  /l  ADFSadapter
  • GAC의 DLL 교체 순서
    1. gacutil.exe /u 로 삭제
    2. C:\ADFSadapter\ADFSadapter.dll 파일 교체
    3. gacutil.exe /if 로 등록

ADFS에 GAC Assembly 등록/삭제 (PowerShell 명령어)

  • ADFS에 등록 먼저, gacutil.exe /l 옵션으로 Version, Culture, public key 정보 확인
PS C:\ADFSadapter> .\gacutil.exe /l ADFSadapter
ADFSadapter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3b3a799d949dc414, processorArchitecture=MSIL
          결과 문자열을 이용하여 TypeName 구성하고, AD FS에 등록
           ( TypeName의 앞부분은 ADFSadapter.AuthenticationAdapter 는 고정값 )

PS C:\ADFSadapter> $typename = "ADFSadapter.AuthenticationAdapter, ADFSadapter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3b3a799d949dc414, processorArchitecture=MSIL"
PS C:\ADFSadapter> Register-AdfsAuthenticationProvider -TypeName $typename -Name "ADFSadapter" -Verbose
  • ADFS에서 삭제
PS C:\ADFSadapter> Unregister-AdfsAuthenticationProvider -Name "ADFSadapter"
  • ADFS에 등록되었는지 확인
PS C:\ADFSadapter> Get-AdfsAuthenticationProvider
  • ADFS의 Adapter 교체 순서

    1. ADFS 관리에서 다단계 인증방법 해제
    2. Unregister-AdfsAuthenticationProvider
    3. ADFS 서비스 재시작
    4. GAC의 DLL 교체
    5. Register-AdfsAuthenticationProvider
    6. ADFS 서비스 재시작
    7. ADFS 관리에서 다단계 인증방법 설정

    상기 step1) ~ step7) 과정은 replace_dll.ps1 스크립트 파일로 자동 처리할 수 있음

MFA 기능이 정상동작하지 않을 경우

  • AD 계정/암호 인증 불가
    → MFA 단계까지 진행되기 전이므로, Adapter와 관련 없음

  • Adapter 등록 상태 확인
    → Get-AdfsAuthenticationProvider 명령어 실행시 ADFS MFA Adapter가 표시되는지 확인

  • AD FS 설정 확인
    서비스 > 인증 방법 > 다단계 인증 방법ADFS MFA Adapter가 지정되어 있는지 확인
    서비스 > 디바이스 등록 설정되어 있는지 확인
    액세스 제어 정책에 MFA 요구를 하도록 설정되어 있는지 확인

  • Adapter 실행 로그 확인
    → 로그 위치 : 컴퓨터 관리 > 시스템 도구 > 이벤트 뷰어 > 응용 프로그램 및 서비스 로그 > MFA_Adapter
    오류로 표시되는 로그가 있는지 확인
    → 오류가 있을시, 개발자에게 로그 내용을 전달해서 분석 요청

Open API guides
Adapter 설정 가이드