Azure Active Directory B2C에서 리소스 소유자 암호 자격 증명 흐름 설정
시작하기 전에 이 페이지의 맨 위에 있는 정책 유형 선택기를 사용하여 설정하려는 정책 유형을 선택합니다. Azure Active Directory B2C는 사용자가 애플리케이션과 상호 작용하는 방법을 정의하는 두 가지 방법, 즉 미리 정의된 사용자 흐름 또는 완전히 구성 가능한 사용자 지정 정책을 통해 제공합니다. 이 문서에서 필요한 단계는 각 방법마다 다릅니다.
Azure AD B2C(Azure Active Directory B2C)에서 ROPC(리소스 소유자 암호 자격 증명) 흐름은 OAuth 표준 인증 흐름입니다. 이 흐름에서 신뢰 당사자라고도 하는 애플리케이션은 토큰에 유효한 자격 증명을 교환합니다. 자격 증명에는 사용자 ID 및 암호가 포함됩니다. 반환되는 토큰은 ID 토큰, 액세스 토큰 및 새로 고침 토큰입니다.
Warning
ROPC 흐름을 사용하지 않는 것이 좋습니다. 대부분의 시나리오에서는 더 안전한 대체 방법을 사용하며 권장합니다. 이 흐름은 애플리케이션에서 매우 높은 신뢰 수준을 요구하며, 다른 흐름에는 없는 위험을 전달합니다. 보다 안전한 다른 흐름을 실행할 수 없는 경우에만 이 흐름을 사용해야 합니다.
ROPC 흐름 정보
Azure AD B2C(Azure Active Directory B2C)에서 지원되는 옵션은 다음과 같습니다.
- 네이티브 클라이언트: 인증 중에 사용자 상호 작용은 코드가 사용자 쪽 디바이스에서 실행되면 발생합니다. 디바이스는 Android 및 iOS와 같은 네이티브 운영 체제에서 실행되는 모바일 애플리케이션일 수 있습니다.
- 공용 클라이언트 흐름: 애플리케이션에서 수집한 사용자 자격 증명만 API 호출로 전송됩니다. 애플리케이션의 자격 증명은 전송되지 않습니다.
- 새 클레임 추가: ID 토큰 콘텐츠를 변경하여 새 클레임을 추가할 수 있습니다.
다음 흐름은 지원되지 않습니다.
- 서버 간: ID 보호 시스템에는 상호 작용의 일부로 호출자(네이티브 클라이언트)에서 수집된 신뢰할 수 있는 IP 주소가 필요합니다. 서버 쪽 API 호출에서는 서버의 IP 주소만 사용됩니다. 실패한 인증의 동적 임계값을 초과하는 경우 ID 보호 시스템은 반복되는 IP 주소를 공격자로 식별할 수 있습니다.
- 기밀 클라이언트 흐름 - 애플리케이션 클라이언트 ID의 유효성은 검사하지만 애플리케이션 비밀의 유효성은 검사하지 않습니다.
ROPC 흐름을 사용하는 경우 다음 제한 사항을 고려합니다.
- 사용자 조작이 필요한 인증 흐름이 중단되면 ROPC가 작동하지 않습니다. 예를 들어 암호가 만료되거나 변경 되어야 하는 경우 다단계 인증 이 필요하거나 로그인하는 동안 추가 정보를 수집해야 하는 경우(예: 사용자 동의).
- ROPC는 로컬 계정만 지원합니다. 사용자는 Microsoft, Google+, Twitter, AD-FS 또는 Facebook과 같은 페더레이션된 ID 공급자를 사용하여 로그인할 수 없습니다.
- KMSI(로그인 유지)를 비롯한 세션 관리는 적용되지 않습니다.
애플리케이션 등록
Azure AD B2C 테넌트에 애플리케이션을 등록하려면 새로운 통합 앱 등록 환경 또는 레거시 애플리케이션(레거시) 환경을 사용하면 됩니다. 새 환경에 대해 자세히 알아보세요.
- Azure Portal에 로그인합니다.
- Azure AD B2C 테넌트가 포함된 디렉터리를 사용하고 있는지 확인합니다.
- 포털 도구 모음에서 디렉터리 + 구독 아이콘을 선택합니다.
- 포털 설정 | 디렉터리 + 구독 페이지의 디렉터리 이름 목록에서 Azure AD B2C 디렉터리를 찾은 다음, 전환을 선택합니다.
- Azure Portal에서 Azure AD B2C를 검색하고 선택합니다.
- 앱 등록을 선택한 다음, 새 등록을 선택합니다.
- 애플리케이션의 이름을 입력합니다. 예를 들면 ROPC_Auth_app과 같습니다.
- 다른 값은 그대로 두고 등록을 선택합니다.
- 이후 단계에서 사용할 애플리케이션(클라이언트) ID를 기록합니다.
- 관리에서 인증을 선택합니다.
- 새 환경(표시된 경우)을 선택합니다.
- 고급 설정의 모바일 및 데스크톱 흐름 허용 섹션에서 예로 선택하여 애플리케이션을 퍼블릭 클라이언트로 처리합니다. 이 설정은 ROPC 흐름에 필요합니다.
- 저장을 선택합니다.
- 왼쪽 메뉴에서 매니페스트를 선택하여 매니페스트 편집기를 엽니다.
- oauth2AllowImplicitFlow 특성을 true로 설정합니다.
"oauth2AllowImplicitFlow": true,
- 저장을 선택합니다.
리소스 소유자 사용자 흐름 만들기
- Azure AD B2C 테넌트의 전역 관리자로 Azure Portal에 로그인합니다.
- 여러 테넌트에 액세스할 수 있는 경우 맨 위 메뉴에서 설정 아이콘을 선택하여 디렉터리 + 구독 메뉴에서 Azure AD B2C 테넌트로 전환합니다.
- Azure Portal에서 Azure AD B2C를 검색하고 선택합니다.
- 사용자 흐름을 선택하고 새 사용자 흐름을 선택합니다.
- ROPC(리소스 소유자 암호 자격 증명)를 사용하여 로그인을 선택합니다.
- 버전에서 미리 보기가 선택되어 있는지 확인한 다음 만들기를 선택합니다.
- ROPC_Auth와 같은 사용자 흐름에 사용할 이름을 입력합니다.
- 애플리케이션 클레임 아래에서 자세히 표시를 선택합니다.
- 표시 이름, 이메일 주소 및 ID 공급 기업과 같은 애플리케이션에 필요한 애플리케이션 클레임을 선택합니다.
- 확인을 선택하고 만들기를 선택합니다.
전제 조건
아직 시작하지 않은 경우 Active Directory B2C에서 사용자 지정 정책 시작에서 사용자 지정 정책 시작 팩을 사용하는 방법을 알아봅니다.
리소스 소유자 정책 만들기
TrustFrameworkExtensions.xml 파일을 엽니다.
BuildingBlocks 요소 아래에서 ClaimsSchema 요소를 찾은 다음, 다음 클레임 형식을 추가합니다.
<ClaimsSchema> <ClaimType Id="logonIdentifier"> <DisplayName>User name or email address that the user can use to sign in</DisplayName> <DataType>string</DataType> </ClaimType> <ClaimType Id="resource"> <DisplayName>The resource parameter passes to the ROPC endpoint</DisplayName> <DataType>string</DataType> </ClaimType> <ClaimType Id="refreshTokenIssuedOnDateTime"> <DisplayName>An internal parameter used to determine whether the user should be permitted to authenticate again using their existing refresh token.</DisplayName> <DataType>string</DataType> </ClaimType> <ClaimType Id="refreshTokensValidFromDateTime"> <DisplayName>An internal parameter used to determine whether the user should be permitted to authenticate again using their existing refresh token.</DisplayName> <DataType>string</DataType> </ClaimType> </ClaimsSchema>
ClaimsSchema 뒤에 ClaimsTransformations 요소와 해당 자식 요소를 BuildingBlocks 요소에 추가합니다.
<ClaimsTransformations> <ClaimsTransformation Id="CreateSubjectClaimFromObjectID" TransformationMethod="CreateStringClaim"> <InputParameters> <InputParameter Id="value" DataType="string" Value="Not supported currently. Use oid claim." /> </InputParameters> <OutputClaims> <OutputClaim ClaimTypeReferenceId="sub" TransformationClaimType="createdClaim" /> </OutputClaims> </ClaimsTransformation> <ClaimsTransformation Id="AssertRefreshTokenIssuedLaterThanValidFromDate" TransformationMethod="AssertDateTimeIsGreaterThan"> <InputClaims> <InputClaim ClaimTypeReferenceId="refreshTokenIssuedOnDateTime" TransformationClaimType="leftOperand" /> <InputClaim ClaimTypeReferenceId="refreshTokensValidFromDateTime" TransformationClaimType="rightOperand" /> </InputClaims> <InputParameters> <InputParameter Id="AssertIfEqualTo" DataType="boolean" Value="false" /> <InputParameter Id="AssertIfRightOperandIsNotPresent" DataType="boolean" Value="true" /> </InputParameters> </ClaimsTransformation> </ClaimsTransformations>
DisplayName
Local Account SignIn
이 있는 ClaimsProvider 요소를 찾아 다음 기술 프로필을 추가합니다.<TechnicalProfile Id="ResourceOwnerPasswordCredentials-OAUTH2"> <DisplayName>Local Account SignIn</DisplayName> <Protocol Name="OpenIdConnect" /> <Metadata> <Item Key="UserMessageIfClaimsPrincipalDoesNotExist">We can't seem to find your account</Item> <Item Key="UserMessageIfInvalidPassword">Your password is incorrect</Item> <Item Key="UserMessageIfOldPasswordUsed">Looks like you used an old password</Item> <Item Key="DiscoverMetadataByTokenIssuer">true</Item> <Item Key="ValidTokenIssuerPrefixes">https://sts.windows.net/</Item> <Item Key="METADATA">https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration</Item> <Item Key="authorization_endpoint">https://login.microsoftonline.com/{tenant}/oauth2/token</Item> <Item Key="response_types">id_token</Item> <Item Key="response_mode">query</Item> <Item Key="scope">email openid</Item> <Item Key="grant_type">password</Item> </Metadata> <InputClaims> <InputClaim ClaimTypeReferenceId="logonIdentifier" PartnerClaimType="username" Required="true" DefaultValue="{OIDC:Username}"/> <InputClaim ClaimTypeReferenceId="password" Required="true" DefaultValue="{OIDC:Password}" /> <InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="password" /> <InputClaim ClaimTypeReferenceId="scope" DefaultValue="openid" /> <InputClaim ClaimTypeReferenceId="nca" PartnerClaimType="nca" DefaultValue="1" /> <InputClaim ClaimTypeReferenceId="client_id" DefaultValue="ProxyIdentityExperienceFrameworkAppId" /> <InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="IdentityExperienceFrameworkAppId" /> </InputClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="oid" /> <OutputClaim ClaimTypeReferenceId="userPrincipalName" PartnerClaimType="upn" /> </OutputClaims> <OutputClaimsTransformations> <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromObjectID" /> </OutputClaimsTransformations> <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" /> </TechnicalProfile>
client_ID의 DefaultValue를 필수 조건 자습서에서 만든 ProxyIdentityExperienceFramework 애플리케이션의 애플리케이션 ID로 바꿉니다. resource_id의 DefaultValue를 필수 조건 자습서에서 만든 IdentityExperienceFramework 애플리케이션의 애플리케이션 ID로 바꿉니다.
기술 프로필을 사용하여 다음 ClaimsProvider 요소를 ClaimsProviders 요소에 추가합니다.
<ClaimsProvider> <DisplayName>Azure Active Directory</DisplayName> <TechnicalProfiles> <TechnicalProfile Id="AAD-UserReadUsingObjectId-CheckRefreshTokenDate"> <Metadata> <Item Key="Operation">Read</Item> <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item> </Metadata> <InputClaims> <InputClaim ClaimTypeReferenceId="objectId" Required="true" /> </InputClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="objectId" /> <OutputClaim ClaimTypeReferenceId="refreshTokensValidFromDateTime" /> </OutputClaims> <OutputClaimsTransformations> <OutputClaimsTransformation ReferenceId="AssertRefreshTokenIssuedLaterThanValidFromDate" /> <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromObjectID" /> </OutputClaimsTransformations> <IncludeTechnicalProfile ReferenceId="AAD-Common" /> </TechnicalProfile> </TechnicalProfiles> </ClaimsProvider> <ClaimsProvider> <DisplayName>Session Management</DisplayName> <TechnicalProfiles> <TechnicalProfile Id="SM-RefreshTokenReadAndSetup"> <DisplayName>Trustframework Policy Engine Refresh Token Setup Technical Profile</DisplayName> <Protocol Name="None" /> <OutputClaims> <OutputClaim ClaimTypeReferenceId="objectId" /> <OutputClaim ClaimTypeReferenceId="refreshTokenIssuedOnDateTime" /> </OutputClaims> </TechnicalProfile> </TechnicalProfiles> </ClaimsProvider> <ClaimsProvider> <DisplayName>Token Issuer</DisplayName> <TechnicalProfiles> <TechnicalProfile Id="JwtIssuer"> <Metadata> <!-- Point to the redeem refresh token user journey--> <Item Key="RefreshTokenUserJourneyId">ResourceOwnerPasswordCredentials-RedeemRefreshToken</Item> </Metadata> </TechnicalProfile> </TechnicalProfiles> </ClaimsProvider>
TrustFrameworkPolicy 요소에 UserJourneys 요소 및 해당 자식 요소를 추가합니다.
<UserJourney Id="ResourceOwnerPasswordCredentials"> <PreserveOriginalAssertion>false</PreserveOriginalAssertion> <OrchestrationSteps> <OrchestrationStep Order="1" Type="ClaimsExchange"> <ClaimsExchanges> <ClaimsExchange Id="ResourceOwnerFlow" TechnicalProfileReferenceId="ResourceOwnerPasswordCredentials-OAUTH2" /> </ClaimsExchanges> </OrchestrationStep> <OrchestrationStep Order="2" Type="ClaimsExchange"> <ClaimsExchanges> <ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" /> </ClaimsExchanges> </OrchestrationStep> <OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" /> </OrchestrationSteps> </UserJourney> <UserJourney Id="ResourceOwnerPasswordCredentials-RedeemRefreshToken"> <PreserveOriginalAssertion>false</PreserveOriginalAssertion> <OrchestrationSteps> <OrchestrationStep Order="1" Type="ClaimsExchange"> <ClaimsExchanges> <ClaimsExchange Id="RefreshTokenSetupExchange" TechnicalProfileReferenceId="SM-RefreshTokenReadAndSetup" /> </ClaimsExchanges> </OrchestrationStep> <OrchestrationStep Order="2" Type="ClaimsExchange"> <ClaimsExchanges> <ClaimsExchange Id="CheckRefreshTokenDateFromAadExchange" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId-CheckRefreshTokenDate" /> </ClaimsExchanges> </OrchestrationStep> <OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" /> </OrchestrationSteps> </UserJourney>
Azure AD B2C 테넌트에서 사용자 지정 정책 페이지에서 정책 업로드를 선택합니다.
정책이 있는 경우 덮어쓰기를 사용하도록 설정하고 TrustFrameworkExtensions.xml 파일을 찾아서 선택합니다.
업로드를 선택합니다.
신뢰 당사자 파일 만들기
다음으로, 만든 사용자 경험을 시작하는 신뢰 당사자 파일을 업데이트합니다.
작업 디렉터리에 SignUpOrSignin.xml 파일의 복사본을 만들고 이름을 ROPC_Auth.xml.
새 파일을 열고 TrustFrameworkPolicy의 PolicyId 특성 값을 고유한 값으로 변경합니다. 정책 ID는 정책의 이름입니다. 예를 들어 B2C_1A_ROPC_Auth입니다.
DefaultUserJourney
ResourceOwnerPasswordCredentials
의 ReferenceId 특성 값을 .로 변경합니다.다음 클레임만 포함되도록 OutputClaims 요소를 변경합니다.
<OutputClaim ClaimTypeReferenceId="sub" /> <OutputClaim ClaimTypeReferenceId="objectId" /> <OutputClaim ClaimTypeReferenceId="displayName" DefaultValue="" /> <OutputClaim ClaimTypeReferenceId="givenName" DefaultValue="" /> <OutputClaim ClaimTypeReferenceId="surname" DefaultValue="" />
Azure AD B2C 테넌트에서 사용자 지정 정책 페이지에서 정책 업로드를 선택합니다.
정책이 있는 경우 덮어쓰기를 사용하도록 설정한 다음, ROPC_Auth.xml 파일을 찾아 선택합니다.
업로드를 선택합니다.
ROPC 흐름 테스트
즐겨 찾는 API 개발 애플리케이션을 사용하여 API 호출을 생성하고 응답을 검토하여 정책을 디버그합니다. POST 요청의 본문으로 다음 정보를 사용하여 이 예제와 같은 호출을 생성합니다.
https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/B2C_1A_ROPC_Auth/oauth2/v2.0/token
- Azure AD B2C 테넌트 이름으로 바꿉
<tenant-name>
다. B2C_1A_ROPC_Auth
를 리소스 소유자 암호 자격 증명 정책의 전체 이름으로 바꿉니다.
키 | 값 |
---|---|
사용자 이름 | user-account |
password | password1 |
grant_type | password |
scope | openid application-id offline_access |
client_id | application-id |
response_type | 토큰 id_token |
user-account
를 테넌트의 사용자 계정 이름으로 바꿉니다.- 사용자 계정의 암호로 바꿉
password1
다. application-id
를 ROPC_Auth_app 등록의 애플리케이션 ID로 바꿉니다.- 새로 고침 토큰을 받으려면 Offline_access 선택 사항입니다.
실제 POST 요청은 다음 예제와 같이 표시됩니다.
POST /<tenant-name>.onmicrosoft.com/B2C_1A_ROPC_Auth/oauth2/v2.0/token HTTP/1.1
Host: <tenant-name>.b2clogin.com
Content-Type: application/x-www-form-urlencoded
username=contosouser.outlook.com.ws&password=Passxword1&grant_type=password&scope=openid+bef22d56-552f-4a5b-b90a-1988a7d634ce+offline_access&client_id=bef22d56-552f-4a5b-b90a-1988a7d634ce&response_type=token+id_token
오프라인 액세스를 사용하는 성공적인 응답은 다음 예제와 같습니다.
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik9YQjNhdTNScWhUQWN6R0RWZDM5djNpTmlyTWhqN2wxMjIySnh6TmgwRlki...",
"token_type": "Bearer",
"expires_in": "3600",
"refresh_token": "eyJraWQiOiJacW9pQlp2TW5pYVc2MUY0TnlfR3REVk1EVFBLbUJLb0FUcWQ1ZWFja1hBIiwidmVyIjoiMS4wIiwiemlwIjoiRGVmbGF0ZSIsInNlciI6Ij...",
"id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik9YQjNhdTNScWhUQWN6R0RWZDM5djNpTmlyTWhqN2wxMjIySnh6TmgwRlki..."
}
새로 고침 토큰 사용
여기에 표시된 것과 같은 POST 호출을 생성합니다. 다음 표의 정보를 요청 본문으로 사용합니다.
https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/B2C_1A_ROPC_Auth/oauth2/v2.0/token
- Azure AD B2C 테넌트 이름으로 바꿉
<tenant-name>
다. B2C_1A_ROPC_Auth
를 리소스 소유자 암호 자격 증명 정책의 전체 이름으로 바꿉니다.
키 | 값 |
---|---|
grant_type | refresh_token |
response_type | id_token |
client_id | application-id |
resource | application-id |
refresh_token | refresh-token |
application-id
를 ROPC_Auth_app 등록의 애플리케이션 ID로 바꿉니다.- 이전 응답에서 다시 전송된 refresh_token 바꿉
refresh-token
다.
성공적인 응답은 다음 예제와 같습니다.
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ilg1ZVhrNHh5b2pORnVtMWtsMll0djhkbE5QNC1jNTdkTzZRR1RWQndhT...",
"id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ilg1ZVhrNHh5b2pORnVtMWtsMll0djhkbE5QNC1jNTdkTzZRR1RWQn...",
"token_type": "Bearer",
"not_before": 1533672990,
"expires_in": 3600,
"expires_on": 1533676590,
"resource": "bef2222d56-552f-4a5b-b90a-1988a7d634c3",
"id_token_expires_in": 3600,
"profile_info": "eyJ2ZXIiOiIxLjAiLCJ0aWQiOiI1MTZmYzA2NS1mZjM2LTRiOTMtYWE1YS1kNmVlZGE3Y2JhYzgiLCJzdWIiOm51bGwsIm5hbWUiOiJEYXZpZE11IiwicHJlZmVycmVkX3VzZXJuYW1lIjpudWxsLCJpZHAiOiJMb2NhbEFjY291bnQifQ",
"refresh_token": "eyJraWQiOiJjcGltY29yZV8wOTI1MjAxNSIsInZlciI6IjEuMCIsInppcCI6IkRlZmxhdGUiLCJzZXIiOiIxLjAi...",
"refresh_token_expires_in": 1209600
}
문제 해결
제공된 애플리케이션이 ‘OAuth’ 암시적 흐름을 허용하도록 구성되지 않음
- 증상 - ROPC 흐름을 실행하고 다음 메시지가 표시됩니다. AADB2C90057: 제공된 애플리케이션이 ‘OAuth’ 암시적 흐름을 허용하도록 구성되지 않았습니다.
- 가능한 원인 - 애플리케이션에 암시적 흐름이 허용되지 않습니다.
- 해결 방법: Azure AD B2C에서 앱 등록을 만들 때 애플리케이션 매니페스트를 수동으로 편집하고 속성
true
값을oauth2AllowImplicitFlow
.로 설정해야 합니다. 속성을 구성한oauth2AllowImplicitFlow
후 변경 내용을 적용하는 데 몇 분(일반적으로 5분 이하)이 걸릴 수 있습니다.
네이티브 SDK 또는 App-Auth 사용
Azure AD B2C는 공용 클라이언트 리소스 소유자 암호 자격 증명에 대한 OAuth 2.0 표준을 충족하며 대부분의 클라이언트 SDK와 호환되어야 합니다. 최신 정보는 최신 모범 사례를 구현하는 OAuth 2.0 및 OpenID 커넥트 네이티브 앱 SDK를 참조하세요.