다음을 통해 공유


엔터프라이즈 애플리케이션용 JWT(JSON Web Token)에서 발급된 클레임 사용자 지정

Microsoft ID 플랫폼은 Microsoft Entra 애플리케이션 갤러리와 사용자 지정 애플리케이션에 사전 통합된 대부분의 애플리케이션과 함께 Single Sign-On을 지원합니다. 사용자가 OIDC 프로토콜을 사용하여 Microsoft ID 플랫폼을 통해 애플리케이션에 인증하면 애플리케이션에 토큰이 전송됩니다. 애플리케이션이 토큰의 유효성을 검사하고 사용하여 사용자 이름과 암호를 묻는 대신 사용자 로그인을 실행합니다.

OIDC 및 OAuth 애플리케이션에서 사용하는 이러한 JWT(JSON Web Token)에는 클레임이라고 하는 사용자에 대한 정보가 포함되어 있습니다. ‘클레임’은 해당 사용자에 대해 발급하는 토큰 내에서 ID 공급자가 사용자에 대해 나타내는 정보입니다. OIDC 응답에서 클레임 데이터는 일반적으로 ID 공급자가 발급한 ID 토큰에 JWT 형식으로 포함됩니다.

소유권 클레임 보기 또는 편집

이 문서의 단계는 시작하는 포털에 따라 약간 다를 수 있습니다.

JWT에서 발급된 애플리케이션에 대한 클레임을 보거나 편집하려면 다음을 수행합니다.

  1. 최소한 클라우드 애플리케이션 관리자Microsoft Entra 관리 센터에 로그인합니다.
  2. ID>애플리케이션>엔터프라이즈 애플리케이션>모든 애플리케이션으로 이동합니다.
  3. 애플리케이션을 선택하고 왼쪽 메뉴에서 Single Sign-On을 선택한 다음 특성 및 클레임 섹션에서 편집을 선택합니다.

애플리케이션은 다양한 이유로 클레임 사용자 지정이 필요할 수 있습니다. 예를 들어, 애플리케이션에 다른 클레임 URI 또는 클레임 값 집합이 필요한 경우입니다. 특성 및 클레임 섹션을 사용하여 애플리케이션에 대한 클레임을 추가하거나 제거할 수 있습니다. 사용 사례에 따라 애플리케이션에 국한된 사용자 지정 클레임을 만들 수도 있습니다.

다음 단계에서는 상수 값을 할당하는 방법을 설명합니다.

  1. 수정할 클레임을 선택합니다.
  2. 조직에 따라 원본 특성에 따옴표 없이 상수 값을 입력하고 저장을 선택합니다.

특성 개요에는 상수 값이 표시됩니다.

특수 클레임 변환

다음 특수 클레임 변환 함수를 사용할 수 있습니다.

함수 설명
ExtractMailPrefix() 메일 주소 또는 사용자 계정 이름에서 도메인 접미사를 제거합니다. 이 함수는 사용자 이름의 첫 번째 부분만 추출합니다. 예를 들어 joe_smith@contoso.com이 아닌 joe_smith입니다.
ToLower() 선택한 특성의 문자를 소문자로 변환합니다.
ToUpper() 선택한 특성의 문자를 대문자로 변환합니다.

애플리케이션별 클레임 추가

애플리케이션 관련 클레임을 추가하려면

  1. 사용자 특성 및 클레임에서 새 클레임 추가를 선택하사용자 클레임 관리 페이지를 엽니다.
  2. 클레임의 이름을 입력합니다. 값은 URI 패턴을 엄격히 따를 필요가 없습니다. URI 패턴이 필요한 경우 네임스페이스 필드에 추가할 수 있습니다.
  3. 클레임에서 해당 값을 검색할 원본을 선택합니다. 원본 특성 드롭다운에서 사용자 특성을 선택하거나 클레임으로 내보내기 전에 사용자 특성에 변환을 적용할 수 있습니다.

클레임 변환

사용자 특성에 변환을 적용하려면

  1. 클레임 관리에서 클레임 원본으로 변환을 선택하여 변환 관리 페이지를 엽니다.
  2. 변환 드롭다운에서 함수를 선택합니다. 선택한 함수에 따라 변환에서 평가할 상수 값과 매개 변수를 제공합니다.
  3. 원본을 다중값으로 처리는 변환을 모든 값에 적용할지 첫 번째 값에만 적용할지를 나타냅니다. 기본적으로 다중값 클레임의 첫 번째 요소는 변환에 적용됩니다. 이 상자를 선택하면 모든 사용자에게 적용됩니다. 이 확인란은 다중값 특성에 대해서만 사용하도록 설정됩니다. 예: user.proxyaddresses.
  4. 여러 변환을 적용하려면 변환 추가를 선택합니다. 한 클레임에 최대 2개의 변환을 적용할 수 있습니다. 예를 들어 user.mail의 메일 접두사를 먼저 추출할 수 있습니다. 그런 다음 문자열을 대문자로 만듭니다.

다음 함수를 사용하여 클레임을 변환할 수 있습니다.

함수 설명
ExtractMailPrefix() 메일 주소 또는 사용자 계정 이름에서 도메인 접미사를 제거합니다. 이 함수는 사용자 이름의 첫 번째 부분만 추출합니다. 예를 들어 joe_smith@contoso.com이 아닌 joe_smith입니다.
Join() 두 특성을 조인하여 새 값을 만듭니다. 필요에 따라 두 특성 사이에 구분 기호를 사용할 수 있습니다. NameID 클레임 변환의 경우 Join() 함수는 변환 입력에 도메인 부분이 있는 경우 특정 동작을 가집니다. 구분 기호 및 선택한 매개 변수와 결합하기 전에 입력에서 도메인 부분을 제거합니다. 예를 들어, 변환의 입력이 'joe_smith@contoso.com이고 구분 기호가 @이고 매개 변수가 fabrikam.com인 경우 이 입력 조합의 결과는 joe_smith@fabrikam.com입니다.
ToLowercase() 선택한 특성의 문자를 소문자로 변환합니다.
ToUppercase() 선택한 특성의 문자를 대문자로 변환합니다.
Contains() 입력이 지정된 값과 일치하는 경우 특성 또는 상수를 출력합니다. 그렇지 않고 일치하는 항목이 없는 경우 다른 출력을 지정할 수 있습니다.
예를 들어 @contoso.com 도메인을 포함하는 경우 값이 사용자의 메일 주소에 해당하는 클레임을 내보내려고 하고, 그렇지 않으면 사용자 계정 이름을 출력하려고 합니다. 이 함수를 수행하려면 다음 값을 구성합니다.
매개 변수 1(입력): user.email
: “@contoso.com”
매개 변수 2(출력): user.email
매개 변수 3(일치 항목이 없는 경우 출력): user.userprincipalname
EndWith() 입력이 지정된 값으로 끝나는 경우 특성 또는 상수를 출력합니다. 그렇지 않고 일치하는 항목이 없는 경우 다른 출력을 지정할 수 있습니다.
예를 들어 직원 ID가 000(으)로 끝나는 경우 값이 사용자의 직원 ID에 해당하는 클레임을 내보내려고 하고, 그렇지 않으면 확장 특성을 출력하려고 합니다. 이 함수를 수행하려면 다음 값을 구성합니다.
매개 변수 1(입력): user.employeeid
: "000"
매개 변수 2(출력): user.employeeid
매개 변수 3(일치 항목이 없는 경우 출력): user.extensionattribute1
StartWith() 입력이 지정된 값으로 끝나는 경우 특성 또는 상수를 출력합니다. 그렇지 않고 일치하는 항목이 없는 경우 다른 출력을 지정할 수 있습니다.
예를 들어 국가/지역이 US로 시작하는 경우 값이 사용자의 직원 ID에 해당하는 클레임을 내보내려고 하고, 그렇지 않으면 확장 특성을 출력하려고 합니다. 이 함수를 수행하려면 다음 값을 구성합니다.
매개 변수 1(입력): user.country
: "US"
매개 변수 2(출력): user.employeeid
매개 변수 3(일치 항목이 없는 경우 출력): user.extensionattribute1
Extract() - 일치 후 지정된 값과 일치하면 부분 문자열을 반환합니다.
예를 들어, 입력 값이 Finance_BSimon이면 일치하는 값은 Finance_이고 클레임의 출력은 BSimon입니다.
Extract() - 일치 전 지정된 값과 일치할 때까지 부분 문자열을 반환합니다.
예를 들어, 입력 값이 BSimon_US이면 일치하는 값은 _US이고 클레임의 출력은 BSimon입니다.
Extract() - 일치 사이 지정된 값과 일치할 때까지 부분 문자열을 반환합니다.
예를 들어 입력 값이 Finance_BSimon_US이면 첫 번째 일치하는 값은 Finance_이고, 두 번째 일치하는 값은 _US이고 클레임의 출력은 BSimon입니다.
ExtractAlpha() - 접두사 문자열의 접두사 알파벳 부분을 반환합니다.
예를 들어, 입력 값이 BSimon_123이면 BSimon을(를) 반환합니다.
ExtractAlpha() - 접미사 문자열의 접미사 알파벳 부분을 반환합니다.
예를 들어, 입력 값이 123_Simon이면 Simon을(를) 반환합니다.
ExtractNumeric() - 접두사 문자열의 접두사 숫자 부분을 반환합니다.
예를 들어, 입력 값이 123_BSimon이면 123을(를) 반환합니다.
ExtractNumeric() - 접미사 문자열의 접미사 숫자 부분을 반환합니다.
예를 들어, 입력 값이 BSimon_123이면 123을(를) 반환합니다.
IfEmpty() 입력이 null이거나 비어 있는 경우 특성 또는 상수를 출력합니다.
예를 들어, 지정된 사용자의 직원 ID가 비어 있는 경우 확장 특성에 저장된 특성을 출력하려고 합니다. 이 함수를 수행하려면 다음 값을 구성합니다.
매개 변수 1(입력): user.employeeid
매개 변수 2(출력): user.extensionattribute1
매개 변수 3(일치 항목이 없는 경우 출력): user.employeeid
IfNotEmpty() 입력이 null이 아니거나 비어 있지 않으면 특성 또는 상수를 출력합니다.
예를 들어, 지정된 사용자의 직원 ID가 비어 있는 경우 확장 특성에 저장된 특성을 출력하려고 합니다. 이 함수를 수행하려면 다음 값을 구성합니다.
매개 변수 1(입력): user.employeeid
매개 변수 2(출력): user.extensionattribute1
Substring() - 고정 길이 문자열 클레임 형식에서 지정된 위치의 문자로 시작하는 부분을 추출하고 지정된 문자 수를 반환합니다.
SourceClaim - 실행해야 하는 변환의 클레임 원본입니다.
StartIndex - 이 인스턴스의 substring에 있는 0부터 시작하는 문자 위치입니다.
Length - substring의 문자 길이입니다.
예시:
sourceClaim - PleaseExtractThisNow
StartIndex - 6
Length - 11
Output: ExtractThis
Substring() - EndOfString 지정된 위치의 문자부터 시작하여 문자열 클레임 형식의 부분을 추출하고, 지정된 시작 인덱스의 나머지 클레임을 반환합니다.
SourceClaim - 변환의 클레임 원본입니다.
StartIndex - 이 인스턴스의 substring에 있는 0부터 시작하는 문자 위치입니다.
예시:
sourceClaim - PleaseExtractThisNow
StartIndex - 6
Output: ExtractThisNow
RegexReplace() RegexReplace() 변환은 입력 매개 변수로 다음을 수락합니다.
- 매개 변수 1: 정규식 입력으로서의 사용자 특성
- 원본을 다중값으로 신뢰하는 옵션
- 정규식 패턴
- 대체 패턴. 교체 패턴에는 정규식 출력 그룹 및 추가 입력 매개 변수를 가리키는 참조와 함께 정적 텍스트 형식이 포함될 수 있습니다.

다른 변환이 필요한 경우 SaaS 애플리케이션 범주 아래의 Microsoft Entra ID 피드백 포럼에 아이디어를 제출합니다.

정규식 기반 클레임 변환

다음 이미지는 첫 번째 변환 수준의 예를 보여 줍니다.

변환의 첫 번째 수준 스크린샷.

다음 표는 변환의 첫 번째 수준에 대한 정보를 제공합니다. 표에 나열된 작업은 이전 이미지의 레이블에 해당합니다. 편집을 선택하여 클레임 변환 블레이드를 엽니다.

작업 필드 설명
1 Transformation 변환 옵션에서 RegexReplace() 옵션을 선택하여 정규식 기반 클레임 변환 방법을 통해 클레임을 변환합니다.
2 Parameter 1 정규식 변환에 대한 입력입니다. 예를 들어, admin@fabrikam.com과 같은 사용자 메일 주소가 있는 user.mail입니다.
3 Treat source as multivalued 일부 입력 사용자 특성은 다중값 사용자 특성일 수 있습니다. 선택한 사용자 특성이 여러 값을 지원하고 사용자가 변환에 여러 값을 사용하려는 경우 원본을 다중값으로 처리를 선택해야 합니다. 선택하면 모든 값이 정규식 일치에 사용되며 그렇지 않으면 첫 번째 값만 사용됩니다.
4 Regex pattern 매개 변수 1로 선택된 사용자 특성 값에 대해 평가되는 정규식입니다. 예를 들어, 사용자의 이메일 주소에서 사용자 별칭을 추출하는 정규식은 (?'domain'^.*?)(?i)(\@fabrikam\.com)$으로 표시됩니다.
5 Add additional parameter 둘 이상의 사용자 특성을 변환에 사용할 수 있습니다. 그러면 특성 값이 정규식 변환 출력과 병합됩니다. 최대 5개의 매개 변수가 추가로 지원됩니다.
6 Replacement pattern 교체 패턴은 정규식 결과에 대한 자리 표시자를 포함하는 텍스트 템플릿입니다. 모든 그룹 이름은 {group-name}과 같은 중괄호로 묶어야 합니다. 관리자가 다른 도메인 이름(예: xyz.com)과 함께 사용자 별칭을 사용하고 국가 이름을 병합하려고 한다고 가정해 보겠습니다. 이 경우 교체 패턴은 {country}.{domain}@xyz.com입니다. 여기서 {country}는 입력 매개 변수의 값이고 {domain}은 정규식 평가의 그룹 출력입니다. 이러한 경우 예상 결과는 US.swmal@xyz.com입니다.

다음 이미지는 두 번째 변환 수준의 예를 보여 줍니다.

클레임 변환의 두 번째 수준 스크린샷.

다음 표는 변환의 두 번째 수준에 대한 정보를 제공합니다. 표에 나열된 작업은 이전 이미지의 레이블에 해당합니다.

작업 필드 설명
1 Transformation 정규식 기반 클레임 변환은 첫 번째 변환으로 제한되지 않으며 두 번째 수준 변환으로도 사용할 수 있습니다. 다른 모든 변환 메서드를 첫 번째 변환으로 사용할 수 있습니다.
2 Parameter 1 RegexReplace()가 두 번째 수준 변환으로 선택된 경우 첫 번째 수준 변환의 출력이 두 번째 수준 변환의 입력으로 사용됩니다. 변환을 적용하려면 두 번째 수준 정규식이 첫 번째 변환의 출력과 일치해야 합니다.
3 Regex pattern 정규식 패턴은 두 번째 수준 변환에 대한 정규식입니다.
4 Parameter input 두 번째 수준 변환에 대한 사용자 특성 입력입니다.
5 Parameter input 관리자는 선택한 입력 매개 변수가 더 이상 필요 없으면 삭제할 수 있습니다.
6 Replacement pattern 대체 패턴은 정규식 결과 그룹 이름, 입력 매개 변수 그룹 이름 및 정적 텍스트 값에 대한 자리 표시자를 포함하는 텍스트 템플릿입니다. 모든 그룹 이름은 {group-name}과 같이 중괄호로 묶어야 합니다. 관리자가 다른 도메인 이름(예: xyz.com)과 함께 사용자 별칭을 사용하고 국가 이름을 병합하려고 한다고 가정해 보겠습니다. 이 경우 교체 패턴은 {country}.{domain}@xyz.com입니다. 여기서 {country}는 입력 매개 변수의 값이고 {domain}은 정규식 평가의 그룹 출력입니다. 이러한 경우 예상 결과는 US.swmal@xyz.com입니다.
7 Test transformation RegexReplace() 변환은 매개 변수 1에 대해 선택한 사용자 특성 값이 패턴 텍스트 상자에 제공된 정규식과 일치하는 경우에만 평가됩니다. 일치하지 않으면 기본 클레임 값이 토큰에 추가됩니다. 입력 매개 변수 값에 대해 정규식의 유효성을 검사하기 위해 변환 블레이드 내에서 테스트 환경을 사용할 수 있습니다. 이 테스트 환경은 더미 값에서만 작동합니다. 추가 입력 매개 변수를 사용하는 경우 매개 변수 이름이 실제 값 대신 테스트 결과에 추가됩니다. 테스트 섹션에 액세스하려면 테스트 변환을 선택합니다.

다음 이미지는 변환 테스트의 예를 보여 줍니다.

변환 테스트 스크린샷.

다음 표는 변환 테스트에 대한 정보를 제공합니다. 표에 나열된 작업은 이전 이미지의 레이블에 해당합니다.

작업 필드 설명
1 Test transformation 닫기 또는 (X) 단추를 선택하여 테스트 섹션을 숨기고 블레이드에서 테스트 변환 단추를 다시 렌더링합니다.
2 Test regex input 정규식 테스트 평가에 사용되는 입력을 수락합니다. 정규식 기반 클레임 변환이 두 번째 수준 변환으로 구성된 경우 첫 번째 변환의 예상 출력이 되는 값이 제공됩니다.
3 Run test 테스트 정규식 입력이 제공되고 정규식 패턴, 교체 패턴입력 매개 변수가 구성되면 테스트 실행을 선택하여 식을 평가할 수 있습니다.
4 Test transformation result 평가에 성공하면 테스트 변환의 출력이 테스트 변환 결과 레이블에 대해 렌더링됩니다.
5 Remove transformation 두 번째 수준 변환은 변환 제거를 선택하여 제거할 수 있습니다.
6 Specify output if no match 정규식 입력 값이 정규식과 일치하지 않는 매개 변수 1에 대해 구성된 경우 변환을 건너뜁니다. 이러한 경우 일치하지 않는 경우 출력 지정을 선택하여 소유권 클레임에 대한 토큰에 추가되는 대체 사용자 특성을 구성할 수 있습니다.
7 Parameter 3 일치하는 항목이 없고 일치하지 않는 경우 출력 지정이 선택된 경우 대체 사용자 특성을 반환해야 하는 경우 드롭다운을 사용하여 대체 사용자 특성을 선택할 수 있습니다. 이 드롭다운은 매개 변수 3(일치하지 않는 경우 출력)에 대해 사용할 수 있습니다.
8 Summary 블레이드 하단에는 변환의 의미를 간단한 텍스트로 설명하는 전체 형식 요약이 표시됩니다.
9 Add 변환에 대한 구성 설정이 확인되면 추가를 선택하여 클레임 정책에 저장할 수 있습니다. 클레임 관리 블레이드에서 저장을 선택하여 변경 내용을 저장합니다.

RegexReplace() 변환은 그룹 클레임 변환에도 사용할 수 있습니다.

변환 유효성 검사

추가 또는실행 테스트를 선택한 후 다음 조건이 발생할 때 메시지가 추가 정보를 제공합니다.

  • 사용자 특성이 중복된 입력 매개 변수는 사용되지 않습니다.
  • 사용되지 않은 입력 매개 변수가 발견되었습니다. 정의된 입력 매개 변수에는 대체 패턴 텍스트에 대한 각각의 사용법이 있어야 합니다.
  • 제공된 테스트 정규식 입력이 제공된 정규식과 일치하지 않습니다.
  • 교체 패턴의 그룹에 대한 원본을 찾을 수 없습니다.

조건에 따라 클레임 내보내기

사용자 유형 및 사용자가 속한 그룹을 기준으로 클레임의 원본을 지정할 수 있습니다.

사용자 형식은 다음과 같을 수 있습니다.

  • 모든 사용자 - 모든 사용자가 애플리케이션에 액세스할 수 있습니다.
  • 멤버: 테넌트의 네이티브 멤버
  • 모든 게스트: Microsoft Entra ID가 있거나 없는 외부 조직에서 이동한 사용자입니다.
  • Microsoft Entra 게스트: 게스트 사용자는 Microsoft Entra ID를 사용하는 다른 조직에 속합니다.
  • 외부 게스트: 게스트 사용자는 Microsoft Entra ID가 없는 외부 조직에 속해 있습니다.

사용자 유형이 도움이 되는 한 가지 시나리오는 애플리케이션에 액세스하는 게스트와 직원에 대한 클레임 원본이 다른 경우입니다. 사용자가 직원인 경우 NameID는 user.email에서 가져오도록 지정할 수 있습니다. 사용자가 게스트인 경우 NameID는 user.extensionattribute1에서 가져옵니다.

클레임 조건을 추가하려면

  1. 클레임 관리에서 클레임 조건을 확장합니다.
  2. 사용자 유형을 선택합니다.
  3. 사용자가 속해야 하는 그룹을 선택합니다. 지정된 애플리케이션에 대한 모든 클레임에서 최대 50개의 고유 그룹을 선택할 수 있습니다.
  4. 클레임에서 해당 값을 검색할 원본을 선택합니다. 원본 특성 드롭다운에서 사용자 특성을 선택하거나 클레임으로 내보내기 전에 사용자 특성에 변환을 적용할 수 있습니다.

조건을 추가하는 순서는 중요합니다. Microsoft Entra는 먼저 원본이 Attribute인 모든 조건을 평가한 다음 원본이 Transformation인 모든 조건을 평가하여 클레임에서 내보낼 값을 결정합니다. Microsoft Entra ID는 동일한 원본의 조건을 위에서 아래로 평가합니다. 클레임은 클레임의 식과 일치하는 마지막 값을 내보냅니다. IsNotEmptyContains와 같은 변환은 제한처럼 작동합니다.

예를 들어 Britta Simon는 Contoso 테넌트의 게스트 사용자입니다. Britta는 Microsoft Entra ID를 사용하는 다른 조직에 속해 있습니다. Fabrikam 애플리케이션에 대한 다음 구성이 주어지면 Britta가 Fabrikam에 로그인하려고 하면 Microsoft ID 플랫폼이 조건을 평가합니다.

먼저 Microsoft ID 플랫폼은 Britta의 사용자 유형이 모든 게스트인지 확인합니다. 유형이 모든 게스트이므로 Microsoft ID 플랫폼에서 클레임 원본을 user.extensionattribute1에 할당합니다. 둘째, Microsoft ID 플랫폼은 Britta의 사용자 유형이 Microsoft Entra 게스트인지 확인합니다. 유형이 모든 게스트이므로 Microsoft ID 플랫폼에서 클레임 원본을 user.mail에 할당합니다. 마지막으로 Britta에 대한 user.mail 값으로 클레임을 내보냅니다.

또 다른 예로 Britta Simon이 다음 구성을 사용하여 로그인을 시도하는 경우를 생각해 보세요. Microsoft Entra는 먼저 원본이 Attribute인 모든 조건을 평가합니다. Britta의 사용자 유형이 Microsoft Entra 게스트인 경우 클레임 원본은 user.mail입니다. 다음으로 Microsoft Entra ID는 변환을 평가합니다. Britta가 게스트이기 때문에 user.extensionattribute1이 클레임의 새 원본입니다. Britta는 Microsoft Entra 게스트에 있으므로 user.othermail이 이 클레임의 새로운 원본입니다. 마지막으로 Britta에 대한 user.othermail 값으로 클레임을 내보냅니다.

마지막 예로 Britta에 구성된 user.othermail이 없거나 비어 있는 경우 어떻게 되는지 생각해 보세요. 클레임은 두 경우 모두 조건 항목을 무시하는 user.extensionattribute1로 돌아갑니다.

보안 고려 사항

토큰을 받은 애플리케이션은 변조할 수 없는 클레임 값을 사용합니다. 클레임 사용자 지정을 통해 토큰 콘텐츠를 수정하면 이러한 가정이 올바르지 않게 될 수도 있습니다. 악의적인 행위자가 만든 사용자 지정으로부터 보호받으려면, 애플리케이션은 토큰을 수정했음을 명시적으로 인정해야 합니다. 다음 방법 중 하나를 사용하여 부적절한 사용자 지정으로부터 보호합니다.

이것이 없으면 Microsoft Entra ID는 AADSTS50146 오류 코드를 반환합니다.

사용자 지정 서명 키 구성

다중 테넌트 앱의 경우 사용자 지정 서명 키를 사용해야 합니다. 앱 매니페스트에서 acceptMappedClaims를 설정하지 마세요. Azure Portal에서 앱을 설정하는 경우 테넌트에서 앱 등록 개체와 서비스 주체를 가져옵니다. 해당 앱은 토큰에서 클레임을 사용자 지정하는 데 사용할 수 없는 Azure 전역 로그인 키를 사용합니다. 토큰에서 사용자 지정 클레임을 가져오려면 인증서에서 사용자 지정 로그인 키를 만들고 서비스 주체에 추가합니다. 테스트용으로 자체 서명된 인증서를 만들 수 있습니다. 사용자 지정 서명 키를 구성한 후 애플리케이션 코드는 토큰 서명 키의 유효성을 검사해야 합니다.

서비스 주체에게 다음 정보를 추가합니다.

인증서의 PFX 파일 내보내기에서 base-64로 인코딩된 프라이빗 및 퍼블릭 키를 추출합니다. “Sign”에 사용되는 keyCredentialkeyIdpasswordCredentialkeyId와 일치하는지 확인합니다. 인증서 지문의 해시를 가져와서 customkeyIdentifier를 생성할 수 있습니다.

Request

참고 항목

서비스 주체에 대한 패치를 시도하기 전에 먼저 Microsoft Entra 관리 센터 앱 등록 블레이드에서 새로 만들어진 앱에 대한 서비스 주체 잠금 구성을 사용하지 않도록 설정합니다. 그러면 400 잘못된 요청이 발생합니다.

다음 예는 서비스 주체에 사용자 지정 서명 키를 추가하는 HTTP PATCH 요청의 형식을 보여 줍니다. keyCredentials 속성의 “key” 값은 가독성을 위해 짧게 표시되었습니다. 값은 base-64로 인코딩됩니다. 프라이빗 키의 경우 속성 사용은 Sign입니다. 퍼블릭 키의 경우 속성 사용은 Verify입니다.

PATCH https://graph.microsoft.com/v1.0/servicePrincipals/aaaaaaaa-bbbb-cccc-1111-222222222222

Content-type: servicePrincipals/json
Authorization: Bearer {token}

{
    "keyCredentials":[
        {
            "customKeyIdentifier": "aB1cD2eF3gH4iJ5kL6-mN7oP8qR=", 
            "endDateTime": "2021-04-22T22:10:13Z",
            "keyId": "aaaaaaaa-0b0b-1c1c-2d2d-333333333333",
            "startDateTime": "2020-04-22T21:50:13Z",
            "type": "X509CertAndPassword",
            "usage": "Sign",
            "key":"cD2eF3gH4iJ5kL6mN7-oP8qR9sT==",
            "displayName": "CN=contoso"
        },
        {
            "customKeyIdentifier": "aB1cD2eF3gH4iJ5kL6-mN7oP8qR=",
            "endDateTime": "2021-04-22T22:10:13Z",
            "keyId": "bbbbbbbb-1c1c-2d2d-3e3e-444444444444",
            "startDateTime": "2020-04-22T21:50:13Z",
            "type": "AsymmetricX509Cert",
            "usage": "Verify",
            "key": "cD2eF3gH4iJ5kL6mN7-oP8qR9sT==",
            "displayName": "CN=contoso"
        }

    ],
    "passwordCredentials": [
        {
            "customKeyIdentifier": "aB1cD2eF3gH4iJ5kL6-mN7oP8qR=",
            "keyId": "cccccccc-2d2d-3e3e-4f4f-555555555555",
            "endDateTime": "2022-01-27T19:40:33Z",
            "startDateTime": "2020-04-20T19:40:33Z",
            "secretText": "mypassword"
        }
    ]
}

PowerShell을 사용하여 사용자 지정 서명 키 구성

PowerShell을 사용하여 MSAL 퍼블릭 클라이언트 애플리케이션을 인스턴스화하고 인증 코드 부여 흐름을 사용하여 Microsoft Graph 대한 위임된 권한 액세스 토큰을 가져옵니다. 액세스 토큰을 사용하여 Microsoft Graph를 호출하고 서비스 주체에 대한 사용자 지정 서명 키를 구성합니다. 사용자 지정 서명 키를 구성한 후 애플리케이션 코드는 토큰 서명 키의 유효성을 검사해야 합니다.

이 스크립트를 실행하려면 다음이 필요합니다.

  • Azure Portal에서 엔터프라이즈 애플리케이션의 애플리케이션 항목 개요 블레이드에 있는 애플리케이션 서비스 주체의 개체 ID.
  • 사용자를 로그인시키고 Microsoft Graph를 호출하는 액세스 토큰을 가져오기 위한 앱 등록. Azure Portal, 앱 등록의 애플리케이션 항목 개요 블레이드에서 이 앱의 애플리케이션(클라이언트) ID를 가져옵니다. 앱 등록에는 다음 구성이 있어야 합니다.
    • 모바일 및 데스크톱 애플리케이션 플랫폼 구성에 나열된 “http://localhost"”의 리디렉션 URI
    • API 권한에서 Microsoft Graph 위임된 권한 Application.ReadWrite.AllUser.Read(관리자에게 이 권한에 대한 동의를 부여해야 함)
  • Microsoft Graph 액세스 토큰을 가져오기 위해 로그인하는 사용자. 사용자는 다음 Microsoft Entra 관리 역할 중 하나여야 합니다(서비스 주체를 업데이트하는 데 필요함).
    • 클라우드 애플리케이션 관리자
    • 애플리케이션 관리자
  • 애플리케이션의 사용자 지정 서명 키로 구성할 인증서. 자체 서명된 인증서를 만들거나 신뢰할 수 있는 인증 기관에서 인증서를 가져올 수 있습니다. 스크립트에서 사용되는 인증서 구성 요소는 다음과 같습니다.
    • 공개 키(일반적으로 .cer 파일)
    • PKCS#12 형식의 프라이빗 키(.pfx 파일)
    • 프라이빗 키의 암호(.pfx 파일)

Important

Microsoft Entra ID는 다른 형식 형식을 지원하지 않으므로 프라이빗 키는 PKCS#12 형식이어야 합니다. Microsoft Graph를 사용하여 인증서 정보가 포함된 keyCredentials로 서비스 주체를 패치하는 경우 잘못된 형식을 사용하면 “잘못된 인증서: 키 값이 잘못된 인증서입니다.”라는 오류가 발생할 수 있습니다.

$fqdn="fourthcoffeetest.onmicrosoft.com" # this is used for the 'issued to' and 'issued by' field of the certificate
$pwd="mypassword" # password for exporting the certificate private key
$location="C:\\temp" # path to folder where both the pfx and cer file will be written to

# Create a self-signed cert
$cert = New-SelfSignedCertificate -certstorelocation cert:\currentuser\my -DnsName $fqdn
$pwdSecure = ConvertTo-SecureString -String $pwd -Force -AsPlainText
$path = 'cert:\currentuser\my\' + $cert.Thumbprint
$cerFile = $location + "\\" + $fqdn + ".cer"
$pfxFile = $location + "\\" + $fqdn + ".pfx"
 
# Export the public and private keys
Export-PfxCertificate -cert $path -FilePath $pfxFile -Password $pwdSecure
Export-Certificate -cert $path -FilePath $cerFile

$ClientID = "<app-id>"
$loginURL       = "https://login.microsoftonline.com"
$tenantdomain   = "fourthcoffeetest.onmicrosoft.com"
$redirectURL = "http://localhost" # this reply URL is needed for PowerShell Core 
[string[]] $Scopes = "https://graph.microsoft.com/.default"
$pfxpath = $pfxFile # path to pfx file
$cerpath = $cerFile # path to cer file
$SPOID = "<service-principal-id>"
$graphuri = "https://graph.microsoft.com/v1.0/serviceprincipals/$SPOID"
$password = $pwd  # password for the pfx file
 
 
# choose the correct folder name for MSAL based on PowerShell version 5.1 (.Net) or PowerShell Core (.Net Core)
 
if ($PSVersionTable.PSVersion.Major -gt 5)
    { 
        $core = $true
        $foldername =  "netcoreapp2.1"
    }
else
    { 
        $core = $false
        $foldername = "net45"
    }
 
# Load the MSAL/microsoft.identity/client assembly -- needed once per PowerShell session
[System.Reflection.Assembly]::LoadFrom((Get-ChildItem C:/Users/<username>/.nuget/packages/microsoft.identity.client/4.32.1/lib/$foldername/Microsoft.Identity.Client.dll).fullname) | out-null
  
$global:app = $null
  
$ClientApplicationBuilder = [Microsoft.Identity.Client.PublicClientApplicationBuilder]::Create($ClientID)
[void]$ClientApplicationBuilder.WithAuthority($("$loginURL/$tenantdomain"))
[void]$ClientApplicationBuilder.WithRedirectUri($redirectURL)
 
$global:app = $ClientApplicationBuilder.Build()
  
Function Get-GraphAccessTokenFromMSAL {
    [Microsoft.Identity.Client.AuthenticationResult] $authResult  = $null
    $AquireTokenParameters = $global:app.AcquireTokenInteractive($Scopes)
    [IntPtr] $ParentWindow = [System.Diagnostics.Process]::GetCurrentProcess().MainWindowHandle
    if ($ParentWindow)
    {
        [void]$AquireTokenParameters.WithParentActivityOrWindow($ParentWindow)
    }
    try {
        $authResult = $AquireTokenParameters.ExecuteAsync().GetAwaiter().GetResult()
    }
    catch {
        $ErrorMessage = $_.Exception.Message
        Write-Host $ErrorMessage
    }
     
    return $authResult
}
  
$myvar = Get-GraphAccessTokenFromMSAL
if ($myvar)
{
    $GraphAccessToken = $myvar.AccessToken
    Write-Host "Access Token: " $myvar.AccessToken
    #$GraphAccessToken = "eyJ0eXAiOiJKV1QiL ... iPxstltKQ"
    
 
    #  this is for PowerShell Core
    $Secure_String_Pwd = ConvertTo-SecureString $password -AsPlainText -Force
 
    # reading certificate files and creating Certificate Object
    if ($core)
    {
        $pfx_cert = get-content $pfxpath -AsByteStream -Raw
        $cer_cert = get-content $cerpath -AsByteStream -Raw
        $cert = Get-PfxCertificate -FilePath $pfxpath -Password $Secure_String_Pwd
    }
    else
    {
        $pfx_cert = get-content $pfxpath -Encoding Byte
        $cer_cert = get-content $cerpath -Encoding Byte
        # Write-Host "Enter password for the pfx file..."
        # calling Get-PfxCertificate in PowerShell 5.1 prompts for password
        # $cert = Get-PfxCertificate -FilePath $pfxpath
        $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($pfxpath, $password)
    }
 
    # base 64 encode the private key and public key
    $base64pfx = [System.Convert]::ToBase64String($pfx_cert)
    $base64cer = [System.Convert]::ToBase64String($cer_cert)
 
    # getting id for the keyCredential object
    $guid1 = New-Guid
    $guid2 = New-Guid
 
    # get the custom key identifier from the certificate thumbprint:
    $hasher = [System.Security.Cryptography.HashAlgorithm]::Create('sha256')
    $hash = $hasher.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($cert.Thumbprint))
    $customKeyIdentifier = [System.Convert]::ToBase64String($hash)
 
    # get end date and start date for our keycredentials
    $endDateTime = ($cert.NotAfter).ToUniversalTime().ToString( "yyyy-MM-ddTHH:mm:ssZ" )
    $startDateTime = ($cert.NotBefore).ToUniversalTime().ToString( "yyyy-MM-ddTHH:mm:ssZ" )
 
    # building our json payload
    $object = [ordered]@{    
    keyCredentials = @(       
         [ordered]@{            
            customKeyIdentifier = $customKeyIdentifier
            endDateTime = $endDateTime
            keyId = $guid1
            startDateTime = $startDateTime 
            type = "X509CertAndPassword"
            usage = "Sign"
            key = $base64pfx
            displayName = "CN=fourthcoffeetest" 
        },
        [ordered]@{            
            customKeyIdentifier = $customKeyIdentifier
            endDateTime = $endDateTime
            keyId = $guid2
            startDateTime = $startDateTime 
            type = "AsymmetricX509Cert"
            usage = "Verify"
            key = $base64cer
            displayName = "CN=fourthcoffeetest"   
        }
        )  
    passwordCredentials = @(
        [ordered]@{
            customKeyIdentifier = $customKeyIdentifier
            keyId = $guid1           
            endDateTime = $endDateTime
            startDateTime = $startDateTime
            secretText = $password
        }
    )
    }
 
    $json = $object | ConvertTo-Json -Depth 99
    Write-Host "JSON Payload:"
    Write-Output $json
 
    # Request Header
    $Header = @{}
    $Header.Add("Authorization","Bearer $($GraphAccessToken)")
    $Header.Add("Content-Type","application/json")
 
    try 
    {
        Invoke-RestMethod -Uri $graphuri -Method "PATCH" -Headers $Header -Body $json
    } 
    catch 
    {
        # Dig into the exception to get the Response details.
        # Note that value__ is not a typo.
        Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ 
        Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
    }
 
    Write-Host "Complete Request"
}
else
{
    Write-Host "Fail to get Access Token"
}

토큰 서명 키 유효성 검사

클레임 매핑을 사용하도록 설정된 앱은 OpenID Connect 메타데이터 요청appid={client_id}를 추가하여 토큰 서명 키의 유효성을 검사해야 합니다. 다음 예제는 사용해야 하는 OpenID Connect 메타데이터 문서의 형식을 보여 줍니다.

https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration?appid={client-id}

애플리케이션 매니페스트 업데이트

단일 테넌트 앱의 경우 애플리케이션 매니페스트에서 acceptMappedClaims 속성을 true로 설정할 수 있습니다. apiApplication 리소스 종류에 설명되어 있습니다. 속성을 설정하면 애플리케이션이 사용자 지정 서명 키 없이 클레임 매핑을 사용할 수 있게 허용합니다.

Warning

악의적인 행위자가 앱에 대한 클레임 매핑 정책을 만들 수 있는 다중 테넌트 앱의 경우 acceptMappedClaims 속성을 true로 설정하지 마세요.

요청받은 토큰 사용자가 Microsoft Entra 테넌트의 확인된 도메인 이름을 사용해야 합니다. 따라서 사용자는 (애플리케이션 매니페스트에서 identifierUris로 표시하는) Application ID URIhttps://contoso.com/my-api로 설정합니다(또는 기본 테넌트 이름을 사용해야 합니다)https://contoso.onmicrosoft.com/my-api.

확인된 도메인을 사용하지 않는 경우 Microsoft Entra ID는 "AcceptMappedClaims는 애플리케이션 GUID가 일치하는 토큰 사용자나 테넌트의 확인된 도메인에 있는 사용자에만 지원됩니다. 리소스 식별자를 변경하거나 애플리케이션별 서명 키를 사용하세요."라는 메시지를 포함하는 AADSTS501461 오류를 반환합니다.

고급 클레임 옵션

SAML 토큰과 동일한 클레임을 노출하도록 OIDC 애플리케이션에 대한 고급 클레임 옵션을 구성합니다. 또한 SAML2.0 및 OIDC 응답 토큰 모두에 대해 동일한 클레임을 사용하려는 애플리케이션의 경우

클레임 관리 블레이드에서 고급 클레임 옵션 아래의 확인란을 선택하여 고급 클레임 옵션을 구성합니다.