1. 들어가며...


Windows 로그인 화면을 커스터마이징 할 때,

Windows XP까지는 GINA(Graphical Identification and Authentication) DLL이 사용되었는데

인터페이스가 어렵고 복잡하며 디버깅도 매우 어려워서 소수 일부 전문가들만 사용했다.


Windows 7(Vista 이상)부터는 Credential Provider(한국어로 번역할 만한 용어가 없어서 그냥 쓴다)

라는 개념으로 비교적 쉽게 수정할 수 있는 API 인터페이스를 제공하고 있다.


그러나 처음 접하는 개발자들에게는 여전히 접근하기에 어렵긴 하다...

개념을 정확하게 이해하기가 어려울 뿐만 아니라

C++에 나름 자신 있는 사람이라 해도 처음 접하는 함수나 시그니쳐 등으로 몹시 당황할 정도니까.




2. Credential Provider의 기본 개념


Credential Provider는 Plugin처럼 여러 개 병렬로 등록 가능하며, 각각 한 가지 인증 처리를 할 수 있는데

이와 같이 추가 Credential Provider를 만들어 할 수 있는 일은,


  • 로그인 화면에 TextBox나 ComboBox 등을 추가한 뒤 추가 입력값(OTP 인증 등)을 받아 검증
  • 기본 Password 로그인 이외에 다른 처리(패스워드 초기화 등)를 함

이상의 두 가지 정도가 대부분이라 할 수 있겠다.


패스워드 인증을 사용하지 않고 스마트카드 인증을 한다거나 지문 인식 인증을 한다거나 등은

OS 및 하드웨어 수준에서 지원이 될 때만 가능한 것이지,

무턱대고 Credential Provider를 만든다고 새로운 인증 방식이 적용되는 것은 아니다.


예를 들어, user/password라는 Windows 계정이 있는데

password 대신에 OTP 코드로 1234라는 값을 입력 받아 인증되게 하려면

별도 사용자 DB에 user:password:OTP와 같은 매핑 테이블이 있어서

OTP 코드로부터 사용자의 password를 조회할 수 있도록 만들어 놓은 경우라면 몰라도,

password를 입력하지 않고 그냥 인증할 수 있는 방법은 없다.


즉,

Credential Provider를 통해 인증을 성공하는 유일한 방법은 ID/Password를 제대로 입력했을 때뿐이다.




3. Credential Provider 추가/삭제/비활성화


앞에서도 잠깐 언급했지만,

Credential Provider를 새로 추가한다는 것은 기본 ID/Password 인증을 사용하지 않고

새로운 형태의 인증 방식을 추가하는 것이다.


따라서 ID/Password 인증 기본 Credential Provider(PasswordProvider)를 수정해서

화면 상에 뭔가 텍스트나 그림 등을 추가할 수 없을까 고민한다면, 그건 잘못된 생각이다.


기본 제공되는 Built-In Credential Provider들은 수정이 불가능하다. (소스 코드를 제공하지 않으니까)

다만, OOP 개념에 따라 새로운 Credential Provider를 만들고 Wrapping하여 Override할 수 있을 뿐.


뭐, 따지고 보면 비슷한 얘기인건가?




아무튼,

Windows 로그인에서 사용되는 Credential Provider들은 모두 위 레지스트리에 등록되어 있다.


HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers



여기서 테스트 목적 또는 필요 시 해당 레지스트리 키를 삭제하지 않고도 "비활성화"시키는 방법이 있는데,


이상의 세 가지 방법이 있다.




4. Credential Provider 테스트/디버깅


Credential Provider를 만들어서 테스트/디버깅을 할 수 있는 방법은 아래 두 가지가 있다.


먼저, 가장 쉽게 디버깅할 수 있는 방법으로는 CredUI라는 로그인 팝업 윈도우를 만들어 실행하는 방법이다.


>> 참조: https://msdn.microsoft.com/en-us/library/windows/desktop/aa375178(v=vs.85).aspx




(아래에 보이는 세 종류의 추가 인증 방식 선택 부분은 원래는 없다.

이번 테스트를 위해 추가한 Credential Provider들이다.)



두 번째는 원래 목적인 Windows 로그인 화면을 통해 확인하는 방법.



(역시 아래에 보이는 세 종류의 추가 인증 방식 선택 부분은 원래는 없다.

이번 테스트를 위해 추가한 Credential Provider들이다.)



이상의 샘플은 Windows 7 이상 버전의 Windows SDK를 설치하면 SDK가 설치된 폴더 하위에

Samples\Security\CredentialProviders 폴더 위치에 C++ 샘플이 설치되는데

그것을 참조하면 된다.



추가로, 아래 사이트를 참조하면 새 Credential Provider를 만들어 보는 데 도움이 많이 된다.


>> 참조1: http://www.sysnet.pe.kr/2/0/1828

>> 참조2: http://www.sysnet.pe.kr/2/0/1829

>> 참조3: https://blogs.msdn.microsoft.com/securitytools/2009/07/30/how-to-build-custom-logon-uis-in-windows-vista/




5. Credential Provider 커스터마이징 범위


Credential Provider로 UI를 수정할 수 있는 부분은 총 9가지 영역이다.


- Large Text

- Small Text

- Edit Text

- Password Text

- Tile Image

- Command Link

- Check Box

- Combo Box

- Submit Button



>> 참조: https://msdn.microsoft.com/en-us/library/windows/desktop/bb648647(v=vs.85).aspx



위 참조 페이지에서 "Credential Provider driven Windows Logon Experience" 링크를 클릭하면

Credential_Provider_Technical_Reference.xps 파일이 다운로드되는데,

해당 파일을 열어 상세히 읽어 보면(특히 CREDENTIAL_PROVIDER_FIELD_TYPE 부분 참조)

많은 도움이 된다.


웹으로는 아래 링크 페이지를 보면 상세한 내용을 알 수 있다.


>> 참조: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762490(v=vs.85).aspx



다른 내용들도 중요하지만,

특히 아이콘(타일 이미지)과 "확인" 버튼은 1개밖에 사용할 수 없는 제약 조건이 있다.

("취소" 버튼은 CredUI에서만이긴 하지만 기본으로, 아예 수정이 불가하다.)






즉, 로그인 화면의 커스터마이징은 딱 이 정도 수준에서만 가능하다.



6. .NET 버전 Credential Provider: pGina


그렇다면 Credential Provider는 C++로만 만들 수 있을까?


뭐 일단은 그렇긴 하다.


그러나 조금 다른 의미에서 .NET으로 확장 가능한 Credential Provider도 있다. pGina라는 이름으로.


>> 참조: http://pgina.org/



그런데, 역시 앞에서 말했듯, pGina라는 이름의 새로운 Credential Provider가 하나 추가된 개념이고,

이 pGina는 ID/Password 기반의 기본 로그인 화면 UI는 건드리지 않고

내부 로직만 Plugin 확장을 통해 추가/수정할 수 있게 해 주는 Credential Provider이다.


>> 참조: https://github.com/pgina/pgina/wiki/How-pGina-Works


pGina logon diagram


pGina components



현재 버전(pGina 3.xx)까지는 Plugin을 통한 UI 수정까지는 지원하지 않고 있으므로

pGina를 이용해서 로그인 화면에 뭔가를 추가하거나 수정한다는 것은 불가능하다.




CredUI로 띄운 pGina 인증 창.

아이콘이 pGina 아이콘으로 표시되고, Service Status 라벨이 추가 표시되는 점이 특징이다.




Windows 로그인 화면으로 보이는 pGina 로그인 창.

역시 아이콘과 Service Status가 보인다.

(Disconnected라고 표시된 것은, 아직 컴퓨터가 네트워크에 연결되지 않았기 때문이다.)




pGina를 이용하여 확장 Plugin을 만들면 아래와 같이 pGina Configuration 화면에서 확인할 수 있는데

여기서 선택/해제하는 간단한 동작만으로 설정이 가능하다.



물론, 이미 얘기했듯, pGina Plugin으로 로그인 화면 UI를 수정하는 것은 불가능하다.

코드 수정을 통해 내부 인증 처리 로직만 수정할 수 있을 뿐이다.




그런데,

pGina를 통해 할 수 있는 일이 하나 더 있다.


바로, Windows에 등록되어 있는 모든 기존 Credential Provider들의 목록을 확인하고

그 중에서 각각 개별적으로 활성화/비활성화시킬 수 있는 기능이다.



이것이 유용한 것은, pGina를 설치하고 난 뒤 Windows의 기본 Credential Provider인 PasswordProvider를
비활성화 해 주어야 비로소 pGina를 통해 수정된 방식으로만 로그인할 수 있게 되기 때문이다.

그렇지 않으면 위 로그인 화면 샘플에서도 보듯, 기본 ID/Password 방식 로그인도 선택할 수 있기 때문에
pGina를 통해 뭔가 추가적인 인증을 거치도록 수정해봤자 그것을 선택하지 않으면 무용지물이 된다.



7. Credential Provider 샘플: Self-Service Password Reset


Credential Provider로 만들 수 있는 것 중,

일반적으로 많이 요구되고, 만들어지는 것이 바로 Self-Service Password Reset 기능이다.

즉, 로그인 화면에 Command Link 또는 별개의 로그인 타일을 두고

클릭하거나 아이디를 입력하면 Password를 초기화하는 단계로 진행되는 기능 말이다.


>> 참조: https://blogs.technet.microsoft.com/aho/2009/11/14/custom-credential-provider-for-password-reset/



위 URL에서 샘플 프로젝트를 내려받아 실행하면 아래와 같은 창까지는 잘 나타난다.






단, "확인" 버튼을 클릭하는 순간 LoadLibrary 오류가 발생한다.

해당 프로젝트는 FIM2010이 설치된 환경에서 동작하도록 되어 있기 때문인데

GateFramework.dll의 RunPwdReset 함수를 호출하여 즉시 암호를 초기화 하도록 샘플이 만들어져 있다.


이것을 힌트로 아래 ExportDLL을 참고하면 .NET C#으로도 동일한 기능을 하도록 만들 수 있다.


>> 참조1: 비 .NET(unmanaged) 에서 호출할 수 있도록 DLL 내보내기

>> 참조2: .NET ExportDLL 오류 처리




8. Credential Provider 실전 예제: Self-Service Password Reset 모듈을 .NET으로 만들어 보기


위 Self-Service Password Reset 샘플 Credential Provider를 이용해서

새 창을 실행하여 SMS 인증을 받은 후 암호를 초기화하는 웹 페이지가 실행되도록 하는

우리나라에서 가장 일반적인 암호 초기화 시나리오를 가정하고

일단 새 창으로 웹 페이지가 실행되는 간단한 .NET 클래스를 만들어 봤다.


using System.Runtime.InteropServices;

using System.Windows.Forms;


public class PasswordReset

{

[ExportDll("RunPwdReset", CallingConvention.Cdecl)]

public static int RunPwdReset(int hwnd, string domain, string userName, string locale)

{

string str = "http://***********/";

string uri = string.Format("{0}", str);

PwResetForm form = new PwResetForm();

form.Width = 800;

form.Height = 600;

form.ShowInTaskbar = false;

form.Uri(uri);

form.ShowDialog();

if (form.DialogResult == DialogResult.OK)

{

form.Close();

}

return 0;

}

}


어셈블리 이름을 "GateFramework"으로 설정하면

위 Self-Service Password Reset 샘플은 전혀 수정하지 않아도 된다.



Tip. 웹 페이지에서 특정 버튼 클릭 시 위에서 실행된 창을 닫도록 하려면 간단하게

Javascript로 window.external.Close();를 실행하면 된다.

windows.external이 IE를 임베딩하고 있는 Form이 되므로 Close() 함수를 바로 호출할 수 있다.



이렇게 실행된 예제는 아래와 같다.



위 Self-Service Password Reset 로그인 화면에서 "domain\userid"를 입력하고 엔터를 치면

위와 같이 팝업으로 새 웹 페이지 창이 잘 실행된다.

그 다음은 비교적 쉬운 웹 페이지 작업만 더 해주면 되는 것이다.




이상으로 Credential Provider에 대해 개략적으로 알아 봤다.


끝.





Posted by 떼르미
,


자바스크립트를 허용해주세요!
Please Enable JavaScript![ Enable JavaScript ]