728x90

SSO(Single Sign On)의 약자 입니다.
단일화면에서 단일 ID와 암호로 한번의 로그인만으로 기업의 각종 업무 시스템이나 인터넷 서비스에 접속할 수 있게 해주는 보안 응용 솔루션으로, 최근 각 기업들의 인트라넷 시스템과 웹서비스가 대폭 확장됨에 따라 급속히 시장이 확대되고 있다.
SSO를 도입하면 각각의 시스템마다의 인증 절차를 밟지 않고도 사용자에 부여된 1개의 계정만으로 다양한 시스템에 접근할 수 있어 사용자 편의가 대폭 높아지고, 관리자 입장에서도 인증정책의 변경이나 권한 설정을 편리하게 적용할 수 있어 비용 절감 및 업무 효율을 높일 수 있다.
특히 최근의 SSO기술은 인증된 사용자에게 시스템 정보 및 자원에 접근할 수 있는 권한은 물론 중요 접근제어 권한까지 부여하는 권한체계관리기반구조(PMI)로 발전되는 추세입니다.

1, 단일 아이디 사용으로 편리성 증대
2. 업무간 이동의 편리성
3. 프로그램 자동인스톨기능으로 사용의 편리
4. 어플리케이션및 시스템관리자의 업무감소
5. 패스워드관리 담당자의 업무 감소

완벽한 보안을 제공하며, id, password에 대한 암기 부담이 감소하며
id, password 기록해 놓을경우, 노출될 수있으나 SSO를 통해 관리할 경우 이러한 위험부담이 감소됩니다.

또 각 어플리케이션간의 이동에 각각의 로그인을 할 필요가 없으므로 클릭만으로 사용하고자 하는 프로그램으로의 이동이 편리해집니다.

여기에 Pass-Ni는 프로그램 자동인스톨 기능이 추가되어 프로그램이 없을경우
프로그램을 다운받아 자동 설치를 지원하므로 사용자뿐만 아니라 시스템이나 프로그램 관리자의 일손을 덜어 줄수 있습니다.

사내 인트라넷 프로그램이나 c/s프로그램의 경우도 아이디 패스워드를 관리하는 담당자의 업무가 대폭 감소합니다.

 

 하나의 아이디로 여러 사이트를 이용할 수 있는 시스템으로 'single sign on'의 첫글자를 따서 SSO라고도 한다. 여러 개의 사이트를 운영하는 대기업이나 인터넷 관련 기업이 각각의 회원을 통합 관리할 필요성이 생김에 따라 개발된 방식으로, 1997년 IBM이 개발하였으며 우리나라에는 2000년 코리아닷컴이 처음 도입하였다. 이후 삼성전자(주)와 SK 등이 도입하며 활성화되어, 애니패스와 오케이캐쉬백·롯데타운 등 다양한 사이트와 네티그리티·다우기술 등 솔루션 공급업체도 많이 설립되었다.

개인의 경우, 사이트에 접속하기 위하여 아이디와 패스워드는 물론 이름·전화번호 등 개인정보를 각 사이트마다 일일이 기록해야 하던 것을 한 번의 작업으로 끝나므로 불편함이 해소되며, 기업에서는 회원에 대한 통합관리가 가능해 마케팅을 극대화시킬 수 있다는 장점이 있다. 특히 권한관리시스템(EAM)과 함께 사용할 경우 보안성과 효율성을 함께 갖춘 통합인증시스템으로 활용할 수 있어 향후 더욱 인기를 끌 것으로 전망된다.

 

 

통합 사용자 인증(SSO): 사용자를 우선적으로 고려해야


 

당신은 ID와 비밀번호를 입력하고 네트워크에 로그온 합니다. 자주 가는 몇 군데 웹사이트와 뉴스그룹을 둘러보고 나니, 이제 일할 시간입니다. 회사 로고로 된 아이콘을 클릭하니, 엄지손가락 지문이나 토큰 코드(token code)를 입력하라는 명령이 나옵니다. 사무실에 있으므로 태블릿을 눌러서 사용허가를 받습니다. 이제 당신은 팀룸(team room), 채팅, 다양한 애플리케이션 등을 사용할 수 있습니다. 게시판에는 당신 고객 중 한 명이 최종 배송품을 수령했다는 메시지가 올라와 있습니다. 그래서, 당신은 그 배송건에 대한 접근권한이 더 이상 없습니다. 그러다, 뭔가 못 보던 것을 발견합니다. 선정해둔 몇 군데 동호회가 당신의 프로필에 있는 이력과 관심사를 보고 당신에게 가입을 권유하고 있습니다. 그리고, 당신은 더 자세한 내용을 알아보기 위해 몇 군데 표시를 해 둡니다.

 


어떻게 이런 일이 가능한가.

비밀번호는 단순히 귀찮은 일 정도가 아니라 장애가 될 수 있습니다. 이런 사실은 긍정적일 수도 있고 부정적일 수도 있습니다. 비밀번호는 정확한 신원확인, 인증, 권한부여, 자원 할당을 보장한다는 점에서 긍정적이지만, 정보시스템 내에서 정보에 기여하고 정보를 필요로 하는 사람들의 적법한 참여를 막는다는 점에서 부정적입니다. 비밀번호 분실에서부터 시스템이 요구하는 특정 문자 조합에 대한 거부반응 등에 이르기 까지 오늘날 비밀번호 방식의 인증이 안고 있는 문제들은 비일비재합니다. 즉 많은 사람들이 무료 웹사이트에서 인증을 요구하면 그 사이트를 아예 피해 버리기도 하고, 인터넷 쇼핑몰에서 물건을 사려다가도 귀찮아서 그만두거나 그냥 일회성 구매면 친구나 가족의 ID를 빌리기도 합니다.

 


통합 사용자 인증(SSO) 기술은 보안을 유지하면서 이런 거부감을 줄이기 위한 시도에서 시작되었습니다. SSO는 사용자도 편할 뿐더러, 비밀번호를 알려달라는 고객 문의를 대폭 줄이고 미결제 고객이나 해고직원의 권한을 빠르고 간편하게 삭제할 수 있게 하여 관리상의 문제를 해결할 수 있습니다. SSO에 대한 접근 기법은 몇 가지 있으며 각각 나름대로의 장단점을 갖고 있습니다.

 

 

 

 


클라이언트 기반(Client-based) - Vince Sorensesn사의 쉐어웨어 소프트웨어인 Password Plus와 같은 비밀번호 관리 도구를 이용하면 사용자는 자체 시스템에 수많은 ID와 비밀번호를 '기억'시키고 PC에서 자동으로 입력하게 할 수 있습니다. 이 과정은 사용자가 설치하고 사용하기에 비교적 편리하지만, 새로운 애플리케이션이나 사이트, 또는 커뮤니티가 추가될 때마다 정보가 갱신되어야 합니다. 그러나, 비밀번호 조합에는 업계 표준이 없기 때문에 문제가 될 수 있습니다. 게다가, PC 중심의 솔루션이라 평소의 작업 장소가 아닌 경우(예를 들어 여행 중)에는 로그인하는 데 번거로워지는 등 사용자 입장에서는 융통성이 부족합니다. 그리고, 기업 네트워크 관리자에게는 조직 전체적으로 통제할 수 있는 방법이 없습니다.

 

 

 

 


서버 기반(Server-based) - 중앙 서버에서 각기 다른 모든 비밀번호를 관리할 수 있습니다. 이 기법을 이용하면, 사용자는 업데이트와 관련한 번거로운 작업(예를 들어, 직무가 변하면 새로운 권한을 인증받는 것)을 하지 않아도 되며, 다양한 PC에서 접근할 수 있습니다. 관리자는 비밀번호의 수준을 관리(예를 들어, 사소한 비밀번호의 삭제, 주기적 갱신, 필요시 접속 중단 등)할 수 있습니다. 또한 서버 기반 시스템의 경우에는 사용자가 여행 중이거나 다른 PC를 사용할 때에도 사용자가 편리하게 이용할 수 있습니다. 서버 기반 기법은 클라이언트 시스템에 대한 보안과 관리 문제뿐만 아니라 사용자와 서버 사이에 존재하는 전반적인 환경까지 처리해야 한다는 것이 제약이라고 할 수 있습니다. 현재 업계 표준이 없기 때문에 더 복잡합니다. 서버 기반 기법에서 사용자가 온라인에서 하는 모든 활동은 서버를 거치기 때문에, 서버는 항상 사용할 수 있어야 합니다

 


서비스 기반(Service-based) - 비밀번호 관리를 하나의 서비스로 제공할 수도 있습니다. 예를 들어, 마이크로소프트 패스포트(Microsoft Passport)는 기업들 가입의 비밀번호 잡무를 처리하기 위해 중앙집중 서버, 쿠키, 표준화된 구조를 이용합니다. 사용자 입장에서는 한번 마이크로소프트 서버에 접속하면 여러 웹사이트에 접속하거나 거래할 때 그 인증이 유지됩니다. 이 방식은 수많은 사이트들이 이 서비스의 제공업자와 제휴된 경우에만 사용자에게 편리합니다. 많은 기업들의 참여를 유도할 수 있는 장점으로는, 다양한 사이트에서 일어나는 사용자들의 활동을 포착할 수 있어서 더 심화된 고객 프로필로 연결될 수 있다는 점입니다. 그러나, 이런 기업측의 이점은 이미 개인정보 보호와 관련된 우려를 낳고 있습니다.

 


이 모든 방식의 경우, 비밀번호는 토큰이나 생체인식을 사용하여 보충 혹은 대체될 수 있습니다. 토큰은 필수적인 키(key)이며 임의로 생성되는 암호를 포함하기도 합니다. 그리고, 생체인식은 엄지손가락의 지문인식과 얼굴인식, 음성인식처럼 사용자의 신체적 특징을 이용합니다. 이 방식은 더 높은 수준의 보안을 보장하지만, 비용 상승, 시스템 간 호환성 문제, false positive(권한이 없는 사용자가 권한이 있다고 잘못 인식), false negative(권한이 있는 사용자가 권한이 없다고 잘못 인식)등의 문제도 일으킵니다.

 


전반적인 SSO의 약점은 일단 인증과정을 통과하게 되면 광범위하게 도용될 수 있기 때문에, 아무리 사소한 침해행위도 개인정보 도용과 맞먹게 된다는 점입니다. 생체인식은 계속 발전하고 있기 때문에 정확한 신원확인을 쉽게 보장할 수 있는 방법이 될 수 있습니다. 그러나, 보안과 접근 용이성 사이에는 쉽게 해결될 수 없는 기본적인 상충관계가 존재하므로 항상 문제는 발생할 것입니다.

 


더구나, SSO는 계속 변하는 사용자의 요구와 권한에 대해 빠르고 융통성 있게 대처할 수 없습니다. 직책이나 인구통계의 경우에서와 마찬가지로, 대부분의 시스템에는 자기 아이디를 숨기지 않고 다니는 사용자도 있고, 규정에만 집착하는 시스템 관리자도 있는 것입니다. 협업 필터링과 커뮤니티를 중요한 입력 수단으로 하면, 실제 신원과 전자적 신원을 긴밀하게 연계할 수도 있을 것입니다.

 


대부분의 SSO 애플리케이션의 전체 설계는 간단하며, 누가 지불하느냐에 따라 사용자나 관리자, 어느 한쪽에 편향되기도 합니다. 어느 누구도 아직까지 보안과 사용의 편의성간의 상충관계를 완벽하게 해결할 수 있는 정말로 혁신적인 SSO 기법을 만들어 내지는 못 했습니다.

 


시사점

기본적으로 통합 사용자 인증(single sign-on)은 획기적 요소나 눈에 띄는 혁신이 없는 기능성 기술입니다. 그러나, SSO는 사용자와 관리자에게 모두 호응을 얻고 있으며, 기존 사용자 및 그간 서비스에 만족하지 못했던 계층에 상당한 영향을 미칠 것으로 전망됩니다.

 


수많은 로그인으로 인한 문제가 계속 늘어나고 있어, IT 기업은 우수한 솔루션을 찾는데 노력을 경주하고 있습니다. 그러나, 이 문제에는 두 가지 면이 있습니다. 예를 들어, SSO 솔루션은 수많은 로그인 솔루션으로 전환되는 기능을 자체적으로 포함할 수 있습니다. 그렇게 되면 로그인 자체의 중요성이 감소됩니다. 분명하고 확실한 솔루션이 나타나지 않는다면, 기업은 솔루션의 장점보다도 마케팅에 좌우되어 솔루션을 구매할 것입니다.

 


개인정보 보호 문제가 SSO의 주요 사안이 되고 있습니다. 일정한 제약이 정보 공유를 통제하기 때문에 이 문제는 더욱 복잡해질 것입니다. 궁극적으로 개인 정보와 프로필의 소유권은 해결 되지 않은 사회문제로 남아 SSO의 가치와 도입에 있어 제약이 될 것입니다. 이상적인 솔루션만이 편의성과 보안 사이에 존재하는 근본적인 상충관계를 해결할 수 있을 것입니다.

 


두 가지 산업: 정부와 금융업 정부와 산하단체간의 다양한 상호작용과 IT 역량으로 인해, SSO는 공공부문에서 확고한 지지기반을 갖고 있습니다. 사실, 여러 단체가 개별적으로 복잡한 이용 제한을 관리할 수 밖에 없다면 여러 면에서 불리합니다. 긍정적인 측면에서 보면 광범위하게 채용된 SSO 애플리케이션은 사용자 요구를 예측하는 데 이용될 수 있으며, 예측된 사용자 요구는 서비스가 제공되는 속도, 그리고 계획과 예산의 기준인 정보를 개선할 수 있을 것입니다.

 


금융업은 보안과 정보 이용 문제가 완전히 상이한 다양한 상품과 서비스를 제공합니다. 예를 들어, 자녀가 부모의 신용카드를 사용하는 것은 허용되지만, 부모의 주식을 파는 것은 허용되지 않습니다. 제 삼자가 대출을 승인한다면, 그 제삼자를 통해 자산 상태가 확인되어야 합니다. 정부는 의무조항과 법률 준수를 위해서 금융기관의 정보 이용이 필요합니다. 내부적으로 금융기관은 다양한 계좌를 관리해야겠지만, 다른 계좌나 특정 정보(신용카드의 구매 성향 등)의 이용할 수 있는 정당한 근거를 갖고 있지 않을 것입니다. SSO는 보안과 정보이용에 관한 다양한 기법들이 각기 다른 수준의 보안 및 복잡한 문제들에 기반한 한 가지 기법으로 모아져 가는 데 필요한 기본 골격(표준 포함)을 제공합니다. 정보의 새로운 결합이 촉진됨에 따라 자금의 움직임과 새로운 제품의 개발이 가능해질 것입니다.

 


주목해야 할 기술

 


암호화(Encryption)

개인 맞춤화(Personalization)

협업 필터링(Collaborative filtering)

XML (Extensible Markup Language)

퍼베이시브 컴퓨팅(Pervasive computing

 

 

 

 

EAM·SSO 기술과 표준화 동향 ①

EAM 시스템과 요구 사항

연·재·목·차

제1회 EAM 시스템과 요구 사항
제2회 SSO 모델과 보안 기술
제3회 SSO·RBAC 표준화 동향


기업의 IT 인프라와 자산에 대한 통합화 및 관리 그리고 통제에 대한 관심이 증대되고 있다. 단순한 사내망에 불과하던 기업 IT 인프라가 직원, 고객, 파트너 등으로 사용자가 확대되면서 다양한 서비스를 요구받기 때문이다. 모든 기업들은 회사의 자원을 보호하고 자원에 대한 접근 권한을 관리함으로써 이러한 복잡한 문제들을 해결하길 바라고 있다. 이러한 기업의 요구에 부합하는 기술적 트렌드를 3회에 걸쳐 연재한다.

강신범 | 소프트포럼 기반기술개발실장


EAM(Extranet Access Management) 시스템은 인트라넷·익스트라넷 서비스를 동시에 수행하는 현재의 기업 IT 인프라 시스템을 안전하게 구성하고 효율적인 관리를 수행할 수 있는 환경 제공을 목적으로 한다.

EAM 시스템에 대한 이해를 돕기 위해 먼저 기업 내 IT 인프라를 EAM 시스템으로 통합하는 시나리오를 간단히 기술하고, 이 시나리오에 근거해서 EAM 시스템의 요구사항을 보안 a기술 측면에서 살펴본다.


EAM 시스템

현재 그룹웨어, 인사관리(HR) 시스템 그리고 전사적자원관리(ERP) 시스템을 운영하고 있는 회사의 경우 각 애플리케이션 별로 각각의 사용자 계정과 권한 관리를 위한 자원이 투입돼 운영된다. 이는 부가적인 관리를 필요로 함은 물론이고 획일적이고 통합되지 않은 상태의 시스템 운영으로 인한 다양한 부작용 및 보안적 결함을 드러내게 된다. 이와 같은 고민에 빠진 회사는 규모의 증대와 IT 인프라 확산에 비례해 보안적 결함이 점차 증가하게 된다. 또한 일정 시일 이후에는 EAM 시스템 도입 비용을 상회하는 기존 시스템의 운영비용으로 인한 손실분을 안게 되는 최악의 상황에까지 몰리게 된다.

이같은 회사가 EAM 시스템을 도입하게 되었을 경우에 회사 내부에서 사용되는 그룹웨어, HR, ERP를 EAM 시스템으로 통합하고 각 애플리케이션별로 개별적으로 관리되던 사용자 계정, 권한관리시스템까지도 단일화된 EAM 시스템에서 통합 관리하게 된다. 이 작업으로 인한 회사의 IT 인프라는 다음과 같이 변경된다.

우선 사내 직원은 사용자 인증을 최초로 한번 받고, 각 애플리케이션을 SSO(Single Sign-On) 기술에 의해 추가 인증없이 사용할 수 있다. 또한 각 애플리케이션은 개인화 서비스를 통해 인증된 사용자의 정보를 얻어 동작에 적용한다.

개별 애플리케이션은 통합된 인가·접근제어 정책에 따라 사용자의 접근을 제어한다. 사내 IT 인프라 관리자는 EAM 관리시스템을 통해 각 애플리케이션별로 접근권한을 사용자에게 제어할 수 있다. 사용자가 통합 인증을 받고 각 애플리케이션에 접근하는 모든 감사정보를 EAM 시스템이 관리해 개별적으로 관리되던 감사정보를 통합해 관리할 수 있게 된다.


EAM 시스템의 요구사항

EAM 시스템은 적어도 다음과 같은 6가지 요구사항 항목을 가진다.

△인증(Authentication):

시스템에 접근하는 사용자를 확인한다. 일반적으로 ID/PWD 방식이 가장 널리 사용되며 보안성을 강화하기 위해 암호, PKI 기술들이 이용된다.

△SSO:

통합 인증된 사용자가 개별 애플리케이션에 추가적인 인증 요구 없이 사용할 수 있어야 한다.

△인가·접근제어(Authorization):

개별 애플리케이션의 각 자원 및 서비스에 대한 인가·접근제어 권한을 관리 툴로 설정하고, 설정된 인가·접근제어 권한이 개별 애플리케이션 동작에 적용이 돼야 한다.

△개인화(Personalization):

통합 인증된 사용자가 개별 애플리케이션에 접근할 때, 접근하는 사용자의 아이덴티티(Identity)와 사용자의 정보를 확인할 수 있는 기술이 제공돼야 한다.

△관리(Administration):

통합 인증을 위한 사용자 계정, 개별 애플리케이션의 인가·접근제어, 개인화를 위한 정보제공의 범위, 감사기능 등을 편리하게 관리할 수 있는 기능이 제공돼야 한다.

△감사(Auditing):

전체 시스템에 접근해 통합 인증을 받고 SSO으로 개별 애플리케이션에 접근, 인가·접근제어가 수행되는 모든 과정이 감사 기록으로 남아야 한다.

<그림> Extranet Computing 환경


인증(Authentication)

EAM 시스템의 요구사항에서 사용자 인증에 관련된 보안 기술은 전체 시스템의 보안성에 매우 중요한 부분을 차지한다. 이와 관련해 EAM 시스템에서 사용될 수 있는 다양한 인증방법 기술에 대해서 소개한다.

인증방법은 기본적인 ID/PWD 방식과 보안성이 상대적으로 높은 X.509 인증서, OTP(One Time Password), 생체인식으로 나뉘어 진다. 아래에서 설명하고 있는 인증 방법들은 일반적인 EAM 시스템에서 웹 환경에 적용하기 적합한 기술들이다.

△Basic ID/PWD:

HTTP/HTTPS 프로토콜의 BASIC Authentication 방법을 이용해 ID와 패스워드로 사용자를 인증한다. 이 인증 방법은 HTTP 프로토콜을 사용하는 경우 사용자가 입력한 ID와 패스워드가 네트워크를 통해 암호화되지 않고 전송된다. HTTPS 프로토콜을 이용하는 경우에는 암호화돼 전달된다.

△Digest Authentication:

HTTP/HTTPS 프로토콜의 Digest Authentica-tion 방법을 이용해 ID와 패스워드로 사용자를 인증한다. 이 인증방법은 패스워드가 평문으로 전달되지 않아 Basic ID/PWD 인증보다 향상된 보안 서비스를 제공하지만, 패스워드가 저장될 때 반드시 패스워드 원본 혹은 복호화될 수 있는 정보로 저장돼야 하기 때문에 서버에서의 패스워드 관리에 각별한 주의가 요구된다.

△Form Based Authentication:

Customized Form(HTML/JSP/ASP etc.)을 이용해 사용자를 확인한다. 폼에 입력되는 인증 정보는 사용자 ID/PWD 만으로 구성될 수도 있고 사용자 ID/PWD 이외의 다른 정보, 예를 들어 사용자 주민등록번호 등을 추가적으로 포함해 사용할 수 있다. 전달되는 정보의 암호화를 위해서는 HTTPS 프로토콜이나 기타 암호 제품을 사용할 수 있다.

△X.509 Client Certificate over SSL:

HTTPS 프로토콜의 사용자 인증서 인증 프로토콜을 이용해 인증한다. 인증서의 폐기 여부 확인을 위해 CRL 검증과 OCSP 검증 방법을 사용할 수 있다.

△One Time Password 인증:

한 번만 사용될 수 있는 패스워드를 이용해 사용자를 인증한다. 사용자에게 미리 전달된 OTP Token을 이용하여 사용자를 인증한다.

△생체 인식:

사용자의 지문이나 홍채 등을 이용해 사용자를 인증한다. 아직은 널리 사용되고 있지 않으나 지문 인식의 경우 그 영역이 확대되고 있는 추세이다.

지금까지 기업의 IT 인프라 관리를 위해 효율성과 보안성을 모두 만족시킬 수 있는 EAM 시스템에 대한 개념과 요구사항을 살펴봤다. 기업의 다양한 IT 시스템 운영에 있어서 보다 안전하고 저비용의 운영 방식을 원한다면 각 애플리케이션 별로 분산돼 있는 인증과 권한 관리 부분을 통합시켜 전사적인 관리가 가능한 EAM 시스템 도입을 고려해 봐야 한다.



연재/EAM·SSO 기술과 표준화 동향 ②

SSO 모델과 보안 기술

강신범
소프트포럼 기반기술개발실장

연·재·목·차

제1회 EAM 시스템과 요구 사항
제2회 SSO 모델과 보안 기술
제3회 SSO·RBAC 표준화 동향

SSO 모델

일반적으로 사용되는 SSO 시스템은 두 가지 모델로 구분된다. SSO 대상 애플리케이션에서 사용되는 사용자 인증 방법을 별도의 SSO 에이전트가 대행해주는 Delegation(인증 대행) 방식과 SSO 시스템과 신뢰관계를 토대로 사용자를 인증한 사실을 전달받아 SSO를 구현하는 Propagation(인증정보 전달) 방식으로 구분된다.

<그림 1> SSO Delegation Model

△Delegation 방식: 대상 애플리케이션의 인증 방식을 변경하기 어려울 때 많이 사용된다. 대상 애플리케이션의 인증 방식을 전혀 변경하지 않고, 사용자의 대상 애플리케이션 인증 정보를 에이전트가 관리해 사용자 대신 로그온 해주는 방식이다. 즉 Target Server 1을 로그온 할 때 User1이 alice/alice라는 ID/ PWD가 필요하다면, 에이전트가 이 정보를 가지고 있고, User1이 Target Service 1에 접근할 때 에이전트가 대신 alice/alice ID/PWD 정보를 전달해서 로그온 시켜준다. △Propagation 방식: 통합 인증을 수행하는 곳에서 인증을 받아 대상 애플리케이션으로 전달할 토큰(Token)을 발급 받는다. 대상 애플리케이션에 사용자가 접근할 때 토큰을 자동으로 전달해 대상 애플리케이션이 사용자를 확인할 수 있도록 하는 방식이다. 웹 환경에서는 쿠키(Cookie)라는 기술을 이용해 토큰을 자동으로 대상 애플리케이션에 전달할 수 있다. 이러한 웹 환경의 이점으로 웹 환경에서의 SSO는 대부분 이 모델을 채택하고 있다.

<그림 2> SSO Propagation Model

△Delegation & Propagation 방식: 웹 환경이라고 하더라도 Propagation 방식이 모두 적용될 수는 없다. 특히 웹 애플리케이션의 변경이 전혀 불가능하고 사용자 통합이 어려운 경우 Delegation 방식을 사용하게 된다. 또한 대상 애플리케이션들이 많이 있고 애플리케이션의 특성들이 다양한 경우 각 애플리케이션에 Delegation 방식과 Propagation 방식을 혼용해서 전체 시스템의 SSO을 구성한다.

△Web 기반 One Cookie Domain SSO: SSO 대상 서비스와 응용 애플리케이션들이 하나의 Cookie Domain안에 존재할 때 사용된다. 일반적인 기업 내부의 컴퓨팅 환경이다. 통합인증을 받은 사용자는 토큰을 발급받게 되고, 이 토큰은 Cookie Domain에 Cookie로 설정되어 Cookie Domain 내의 다른 서비스로 접근할 때 자동으로 토큰을 서비스에 제공하게 된다. 서비스에서 동작되는 SSO 에이전트는 토큰으로부터 사용자 신원을 확인하고 요청된 자원에 대한 접근을 허가 해준다.

Web 기반 Multi Cookie Domain SSO

SSO 대상 서비스와 응용 애플리케이션들이 여러 도메인으로 분산돼 있을 경우다. Multi Domain 환경인 경우에는 사용자 인증 및 토큰의 발행을 위한 마스터 에이전트가 존재한다.
마스터 에이전트는 각 서비스 에이전트의 사용자 인증을 위임받아 수행한다. 인증된 사용자에게는 토큰을 발급하고 각 서비스 에이전트에게 안전하게 전달한다. 또한 에이전트가 해당 토큰을 자신의 Domain에서 Cookie로 저장해 사용할 수 있도록 한다. 각 서비스 에이전트의 신뢰도 및 SSO 시스템의 보안 레벨에 따라 다음과 같이 두 가지 방식으로 서비스될 수 있다.

<그림 3> One Token for All Multi Cookie Domain

△One Token for All Multi Cookie Domain: 모든 도메인이 하나의 토큰을 공유한다. 모든 시스템은 서로 신뢰관계를 가져야 한다. 토큰이 하나만 사용되므로, 마스터 에이전트는 사용자 인증 및 각 도메인에 대한 토큰 제공에 대해서만 수행하게 돼 에이전트들의 관리 및 구성이 매우 간단하다. 하지만 모든 도메인들이 서로 신뢰관계를 가져야 한다는 제약사항으로 인해 적용대상이 제한적이다. 일반적으로 하나의 기업에서 운영하는 다중 도메인 서비스들을 SSO로 구성할 때 많이 사용된다.

<그림 4> One Token form each cookie domain & One Token for Master Agent

△One Token for each cookie domain & One Token for Master Agent: 마스터 에이전트와 각 도메인들이 각각 토큰을 가진다. 마스터 에이전트는 각 도메인의 에이전트들과 신뢰관계를 가지며, 각 도메인의 에이전트들 사이는 신뢰관계를 가지지 않는다. 마스터 에이전트는 각 도메인의 에이전트에게 전달할 사용자 토큰을 발행하므로, 에이전트들의 레벨이나 속성에 따라 토큰에 저장되는 사용자 정보의 양을 조절할 수 있다. 토큰이 각 도메인 별로 발행되므로, 도메인별 Replay Attack 등에 대한 취약성이 전체 시스템에 영향을 주지 않는다.

SSO 보안 기술

토큰은 쿠키를 통해 전달되므로 외부에 노출되는 정보이다. 완벽한 보안을 위해서는 토큰이 네트워크에서 노출되어서는 안되지만, 비용 및 관리상의 이유로 허용되고 있다. 하지만 토큰을 통해 토큰이 포함하고 있는 정보까지 외부에 노출하는 것은 심각한 결함을 제공한다. 토큰의 네트워크 구간에서의 정보 노출 및 위·변조를 방지하기 위해 다음과 같은 보안기술이 사용된다.

△Data Confidentiality: 토큰은 주요 암호 알고리즘(AES, SEED)과 128bit 이상의 키로 암호화돼 보호되어야 한다. △Data Integrity: 토큰은 MAC

(Message Authentication Code) 등을 포함해 데이터의 무결성을 보장해야 한다. △Replay Attack Protection: 토큰은 사용자와 대상 애플리케이션 사이에 전달되는 인증 정보이다. 일반적으로 토큰은 네트워크에 노출되며, 노출된 토큰을 사용해 다른 사용자가 인증을 받고 들어올 수 있다(Replay Attack). 특히 웹 환경에서 이러한 문제점이 중요한 이슈로 등장하고 있다. 이러한 문제점을 근본적으로 해결하기 위해서는 토큰을 네트워크에 노출시키지 않아야 한다.
토큰을 네트워크에 노출시키지 않기 위해서는 항상 사용자와 대상 애플리케이션 사이에 암호 채널을 형성해야 하며, 이 채널을 통해 토큰을 전달해야 한다. 그러나 SSL과 같은 채널 암호를 사용하는 데에는 매우 많은 비용이 요구되어 실제로 많이 사용되고 있지는 않다.
SSL과 같은 암호채널을 사용하지 않으면서 Replay Attack이 발생할 수 있는 상황을 줄일 수 있도록 다음과 같은 보안 기술들이 사용된다.

△사용자 주소 제한: 토큰이 발행될 때 접속한 사용자 주소 정보를 토큰 내부나 토큰을 발행한 서버에서 기억함으르써 Token이 제출된 사용자 주소와 최초 발행시 기억된 주소를 비교하여 접속한 곳 이외에서의 접속을 제한할 수 있다. 사용자 주소가 업무진행 중에 자주 변경되지 않는 시스템일 경우 유효하다. 예를 들어 회사내의 인터넷 환경일 경우 사용될 수 있다. 인터넷 환경의 경우에는 사용자 주소가 특정 범위에서 자주 바뀔 수 있는 환경도 있기 때문에 불특정 다수를 위한 일반적인 인터넷 서비스에 사용하기에는 부적합하다.

△유효시간 제한: 토큰의 유효시간을 매우 짧게 줌으로써 Replay Attack에 사용될 수 있는 시간을 제한한다. 유효시간내에 임계시간(예: 유효시간의 1/2)을 넘으면 자동으로 토큰을 재 발행하여 사용자는 의식하지 못하고 서비스를 계속 사용하게 한다. 지금까지 사용자가 각 애플리케이션별로 별도의 인증을 받지 않고, 한번의 통합 인증만으로 각 애플리케이션들을 사용할 수 있도록 하는 SSO 기술에 대해 살펴보았다. 대상 애플리케이션의 수정을 최소화할 수 있는 Delegation 모델과 토큰을 생성해 통합 인증 서비스를 제공하는 Propagation 모델 그리고 양자의 장점을 조합한 Delegation & Propagation 방식을 이해한다면 현재 도입 대상 기업의 IT 인프라와 진행중인 서비스 및 애플리케이션의 특성에 적합한 EAM 시스템 도입을 결정하는데 도움이 될 것이다.

EAM·SSO 기술과 표준화 동향

제3회 SSO·RBAC 표준화 동향


강신범
소프트포럼 기반기술개발실장

연·재·목·차
제1회 EAM 시스템과 요구 사항
제2회 SSO 모델과 보안 기술
제3회 SSO·RBAC 표준화 동향

SSO 표준화 동향

네트워크 아이텐티티 관리에 대한 오픈 표준안을 개발하는 Liberty Alliance 프로젝트와 SAML(Security Assertion Markup Language) 표준안을 개발하는 OASIS Security Services TC의 활동을 통해 EAM 보안 기술의 동향을 살펴보자.

Liberty Alliance Project

Liberty Alliance Project는 2001년 9월 연합 네트워크 아이텐티티 관리와 아이텐티티 기반 서비스를 위한 오픈 표준안을 개발하기 위해서 구성됐다. 주된 목표는 상호운영성을 보증하고 개인의 사적자유를 지원하며, 이 스펙과 가이드라인 그리고 실행이 최대한 될 수 있도록 진행하는 것이다. 이 연합은 전 세계의 교육 기관과 정부기관에서부터 서비스 제공자와 금융 기관, 기술관련 회사들과 무선 서비스 제공자들까지 1백50여 멤버 이상으로 구성돼 있다.
Liberty Alliance Project는 오픈 스펙을 개발하는 것으로 특정한 제품이나 서비스에는 제공하지 않는다. 연합의 목적은 다른 현존하는 산업 표준들을 지원하는 스펙을 개발하고, 연합의 멤버들과 다른 기관들이 상호 운영될 수 있는 제품과 서비스를 개발하는데 필요한 수단을 개발하는 것이다. 또한 비용을 감소하면서 안전한 연합 아이텐티티 관리도 진행한다.

Security Services TC(SSTC)

Security Services TC는 OASIS(Organization for the Advancement of Structured Information Standards) 표준안인 Security Assertion Markup Language(SAML) 표준안을 마련하는 그룹이다. OASIS는 시장에서의 상호 운영성을 중심으로 보안, 웹서비스, XML 표준, 상거래, 전자 출판 등의 세계 표준안을 만든다.
SAML은 인증 및 인가 정보를 교환하는 XML 프레임워크다. 2002년 11월 SAML 1.0 스펙이 OASIS 표준안으로 인정됐으며, 지난해 9월 SAML 1.1 스펙이 표준안으로 인정됐다. 현재는 SAML 2.0 스펙을 위한 작업이 진행 중이다.

RBAC 표준화 동향

한편 미국 NIST RBAC 그룹의 활동을 중심으로 현재 제안중인 NIST RBAC Standard 문서의 내용에 기초해 RBAC 보안기술 동향을 살펴보자.
Role Based Access Control 모델은 1992년 David Ferraiolo와 Rick Kuhn에 의해서 소개됐다. 이후 소프트웨어 개발 업체들이 자신들의 제품과 데이터베이스 관리시스템, 보안 관리 및 네트워크 관리시스템 등에 RBAC의 기능들을 구현하기 시작했다. 그러나 표준화된 기능 정의가 없이 구현돼 RBAC의 유용성과 의미가 불확실하고 혼돈을 초래하게 됐다. 이러한 문제들과 미국 정부와 산업체들의 RBAC 기능에 대한 명확한 정의 요구를 받아들여 미국 National Institue of Standard and Technology(NIST)에서 RBAC(Role Based Access Control) 표준안을 개발하게 됐다.
첫번째 RBAC 표준안 드래프트는 2000년 ACM Workshp on Role Based Access Control에서 제안됐다. 두번째 버전은 2001년 InterNational Com-mittee for Information Technology Standards(INCITS)에 제출됐다. INCITS BSR 359의 공개 리뷰는 INCITS Technical Committee T4로부터 비평을 받았고, 이에 근거해서 이후 작은 변화들이 있어 왔다. 현재는 표준안 문서(NIST-RBAC-STD DRAFT)로 변화됐다.
RBAC Model & Specification
NIST-RBAC-STD DRAFT 문서는 RBAC Reference Model과 RBAC System and Administrative Functional Specification으로 구성돼 있다.

▲RBAC Reference Model

RBAC Reference Model은 기본 RBAC 요소들(USER, ROLE, PER-MISSION, OPERATION, OBJECT)과 표준안에 포함돼 있는 각 TYPE 및 함수들의 관계를 정의한다. 이 표준안은 RBAC Reference Model로 다음과 같은 네 가지 모델을 정의한다.
CORE RBAC: Core RBAC은 RBAC 시스템이 완전히 구성되기 위한 RBAC 요소들, 요소 집합과 관계들의 최소한의 모음을 정의한다. RBAC 시스템에서 기본적으로 고려되는 USER-ROLE 할당, PERMISSION-ROLE 할당 관계를 포함한다. 여기에 ROLE 활성화 개념도 포함하고 있다.
Hierarchical RBAC: Hierarchical RBAC은 ROLE 계층을 지원하는 관계들을 추가한다. 계층은 수학적으로 Partial Order 관계로서 Role 사이의 상속 관계를 다음과 같이 정의한다. 상위 Role은 하위 Role들의 PERMISSION을 가지고, 하위 Role들은 상위 Role의 사용자들을 가진다. 여기에 더해서 Authorized User와 Authorized Permission 개념을 도입해서 상속 관계로 인한 추가적인 정보를 얻을 수 있는 기능을 포함한다.
Static Separation of Duty Relations: Static Separation of Duty 관계는 사용자 할당과 관련해서 Role 사이의 배타적인 관계를 지원한다. Static Separation of Duty와 Role 계층과는 중요한 불일치성이 발생하기 때문에 SSD 관계는 Role 계층이 있을 때와 없을 때의 관계에 대해서 따로 정의한다.
Dynamic Separation of Duty Relations: Dynamic Separation of Duty 관계는 사용자세션의 일부로서 활성화된 Role 들에 대해서 배타적인 관계를 설정한다.

▲RBAC System and Administrative Functional Specification

RBAC System and Administrative Functional Specification은 RBAC 시스템이 요구하는 기능들을 명기하고 있다. 이들 기능들은 administrative operations, administrative reviews, system level functionality 세 부분으로 분류된다.
Administrative Operations: RBAC 요소들과 관계들을 생성, 삭제, 그리고 관리하는 기능을 제공하는 함수들을 정의한다.
Administrative Review: RBAC 요소들과 관계들에 대한 질의를 수행하는 기능을 제공하는 함수들을 정의한다.
System level functionality: ROLE 활성화·비활성화를 포함한 사용자 세션 생성, Role 활성화를 위한 제약조건, 그리고 접근 결정 연산을 위한 기능들을 정의한다.
지금까지 EAM·SSO 시스템을 구성하기 위한 기본적인 요소들과 각종 보안기술, 그리고 표준화 동향에 대해 살펴봤다.
EAM·SSO 시스템은 웹 환경이 발전해 가면서 상업 솔루션들을 중심으로 개별 회사·서비스 별로 구축돼 왔다. 또한 각 기술들이 제품 별로 구현되면서 같은 개념으로부터 출발한 기술들이 점점 다른 점을 갖게돼 상호운영성 문제나 개념의 혼돈 상황을 맞이하게 됐다.
이러한 점을 표준화를 통해 해결하고자 상업적으로 독립된 기관과 각 솔루션 업체들이 공동으로 참여해 표준화 노력이 진행되고 있다. 이 문서에서 소개한 Liberty Alliance, SAML, RBAC 모두 표준안의 제시와 함께 솔루션 적합성 테스트를 위한 방안을 제시하고 있다.

728x90

www.chariotsolutions.com/slides/osconf2005-security.pdf

Open Source in the Corporate World

Open Source Single SignOn

Erin Mulder
Copyright 2005 Chariot Solutions

Agenda

• Introduction
• Single SignOn for Multiple Applications
– Shared directory (e.g. OpenLDAP)
– Proxy systems (e.g. Yale CAS)
– X.509 certificates
– NTLM
– Kerberos/SPNEGO
• Integration with Workstation Login
– Shared directory
– Kerberos
• CrossDomain & Federated Single SignOn

Proxy Systems

• User accesses web application and is redirected to authentication web app
• Authenticator collects username/password and validates against central auth store
• Sets a cookie and redirects user back to original application
• Application communicates with authenticator to ensure

• Advantages
– User only has to log in once per “session” to access multiple web applications
– Credentials are only passed across wire once
– Applications don’t need to trust each other

• Disadvantages
– Still requires at least one login per browser “session”
– Credentials are still passed across network
– Applications have to communicate with authenticator to validate cookie
Doesn’t integrate seamlessly with J2EE declarative security (though you can usually fake this)

• Implementing with Open Source
– Check out the Central Authentication Service (CAS) project
– Most widely used implementation is Yale CAS Server
– Hook up to an auth store with CAS Generic Handler
– Get started in minutes with the “Quick Start” packages distributed by ESUPPortail, which include:
  • Yale CAS Server
  • Tomcat
  • CAS Generic Handler (CGH)
  • Ant scripts to install and run it all
– CASFilter supports protecting your application’s pages with
Servlet filters, JSP custom tags and direct API calls 

Cross Domain SSO

 • Cookies don’t work
• Client certificates do work
• Kerberos supports domain trust relationships
• Yale CAS 2.0 supports proxy ticketing
• Plenty of standards (Liberty, SAML, etc.) but little stable open source support
• Keep an eye on this area, but look to commercial tools for outofthebox features

'참고자료 > SSO' 카테고리의 다른 글

SSO(Single Sign On)  (0) 2009.02.13
싱글사인온(single sign-on)으로 엔터프라이즈 자바 인증을 단순하게!  (0) 2009.02.13
DB를 이용한 SSO 구현 방법론  (0) 2009.02.13
Single Sign On  (0) 2009.02.13
SSO 적용 모델  (0) 2009.02.13
728x90

점점 더 많은 패스워드 보안 애플리케이션을 조직의 컴퓨터 환경에 추가한다면 이는 인증의 복잡함도 함께 가중시키는 것이고 결국 개발자와 사용자에게 부담을 주게 된다. 대부분의 엔터프라이즈 애플리케이션 통합 프로젝트들은 싱글사인온(SSO) 기능을 포함하고 있다. 이는 사용자가 다양한 애플리케이션을 사용하기 위해 단 한번만 로그인 하도록 하는 기능이다. 이 글에서 자바 플랫폼에 SSO를 구현하는 방법을 설명한다.

 

당신의 기업은 많은 자바 애플리케이션들을 구동하고 있으며 그 엔터프라이즈 리소스에 접근하기 위해서는 인증이 필요합니까? 그렇다면 싱글사인온(SSP) 보안 기능을 구현하여 사용자 침입을 최소화 할 필요가 있다. 이 글에서 Kerberos와 Java Generic Security Services API (GSS-API)를 사용하여 SSO를 구현하는 방법을 배우게 될 것이다. 우선 SSO의 정의를 설명하고 강력한 애플리케이션을 설명할 것이다. 그런 다음 Kerberos 기반의 SSO를 구현할 때 발생하는 메시지 교환 시퀀스도 연구한다. 자바 GSS-API와 GSS를 사용하여 SSO를 달성하는 전형적인 자바 애플리케이션 아키텍쳐를 간단히 소개한다. 마지막으로 이 모두를 종합하여 코드 예제를 선보인다. 자바 개발자가 GSS Kerberos 티켓으로 SSO를 어떻게 구현하는지 보게 될 것이다.

 

코드

j-gss-sso.zip (다운로드) 파일에는 이 글에 사용된 모든 코드가 포함되어 있다. 이 글의 각 리스팅은 파일 이름이 포함되어 있는 주석으로 시작한다. 이 이름들을 사용하여 각 리스팅을 j-gss-sso.zip 아카이브에 있는 상응하는 파일에 매치한다. 이 아카이브에는 Setup.txt 파일도 있다. 코드 실행 전에 이 파일을 읽기 바란다.

 

싱글사인온'이란 무엇인가?

근본적으로 싱글사인온 인증이 의미하는 것은 인증 데이터의 공유이다. 예를 들어 웨어하우징 회사의 많은 사원들은 엔터프라이즈 리소스(데이터베이스 테이블 등)에 접근하여 그들의 업무에 필요한 것을 수행해야 한다. 동시에 다른 사원들도 작업 내용에 따라 다양한 리소스가 필요하다. 회계 담당자는 회계 관련 데이터베이스 테이블에 접근해야 하는 반면 판매 담당자는 판매 관련 데이터베이스 테이블에 접근해야 한다. CEO라면 기업의 데이터베이스 어디에나 접근이 필요할 것이다.


분명한 것은, 이 기업은 무엇보다도 제대로 된 인증 메커니즘이 필요하다. 어떤 사원이 특정 리소스에 접근을 시도했는지 결정할 수 있도록 말이다. 일단 기업 인증 모듈이 사원의 존재를 알면 엔터프라이즈 구현 안의 인증 모듈은 인증이 있는 사용자가 적절한 권한을 갖고 리소스에 접근했는지의 여부를 검사할 수 있다. 사원들이 인증용 유저네임과 패스워드를 사용한다고 가정해보자. 이 기업의 인증 모듈은 당연히 유저네임과 패스워드의 데이터베이스를 갖고 있을 것이다. 들어오는 인증 요청은 유저네임-패스워드 쌍으로 동반될 것이다. 이 인증 모듈은 내부 데이터베이스의 쌍과 비교를 하게 된다.

이제 우리의 웨어하우징 회사는 이 범위안에서 실행되는 여러 애플리케이션들을 갖고있다. 다양한 애플리케이션들이 같은 엔터프라이즈의 다른 모듈을 형성한다. 각각의 애플리케이션은 그 자체로 완벽하다. 이것 나름대로 사용자 기반의 여러 다른 티어(백엔드 데이터베이스, 비지니스 로직, 사용자용 GUI)를 갖고있다는 것을 의미한다. 엔터프라이즈 애플리케이션 통합(EAI)는 이와 같은 독립된 애플리케이션들을 하나의 엔터프라이즈에 통합하는 프로젝트를 일반적으로 가르킨다.

EAI 프로젝트에서 인증 프로세스에 두드러지는 하나의 일반적인 요소가 있다. 특정 애플리케이션의 사용자는 그 엔터프라이즈 내의 또 다른 애플리케이션에 액세스 해야한다. 예를 들어 판매 데이터베이스를 사용하고 있는 판매 담당자가 특정 부품을 검색하기 위해 재고 데이터베이스에 액세스 해야 할 경우도 있다. 이러한 유형의 크로스-애플리케이션 인증을 실현시킬 수 있을까? 두 가지 선택이 있다

  • 두 애플리케이션에서 유저네임과 패스워드 데이터베이스를 중복시킬 수 있다. 따라서 이러한 두 개의 애플리케이션들이 웨어하우징 회사의 모든 사원들을 위해 인증 요청을 효율적으로 처리할 수 있도록 하는 것이다. 사용자는 두 개의 애플리케이션에서 개별적으로 인증을 처리하게 된다. 다시 말해서 자신의 유저네임과 패스워드로 들어가면서 두 애플리케이션 중 하나에 액세스하고 그 애플리케이션은 모든 인증 단계를 수행하게 된다. 유저네임과 패스워드 데이터베이스를 중복할 뿐만 아니라 인증 프로세스 오버헤드까지 중복하는 것이다. 이 솔루션에서 중복의 양은 명확해진다.

  • 두 번째 선택은 판매 애플리케이션과 재고 애플리케이션 간 싱글사인온을 통한 인증 데이터 공유를 가능하게 하는 것이다. 만일 사용자가 한 애플리케이션 인증을 갖고 있다면 그의 인증 정보는 다른 것에 전달 될 수 있다. 이 두 번째 애플리케이션은 그 모든 인증 단계를 거치지 않고도 인증 정보를 수락한다. 이 솔루션에는 중복이 없다. 두 개의 애플리케이션이 서로 신뢰하여 각 애플리케이션이 서로의 인증 데이터를 수락할 수 있도록 하는 것이 유일한 필요조건이다.

    일반적으로 SSO는 개별 인증 모듈로서 구현된다. 사용자 인증이 필요한 모든 애플리케이션들은 SSO 기반의 인증 모듈에 의지하여 사용자를 확인한다. 이 인증 정보에 따라 다양한 애플리케이션들은 각자의 인증 정책을 발효한다.

    이 웨어하우징 기업 예제는 사용자 관점에서 SSO가 무엇인지를 설명한 것이다. 다음 질문은 당연히 "SSO를 어떻게 구현하는가?"이다. 여러 방법이 있다. SSO를 포함하여 다양한 보안 서비스를 제공하는 Kerberos에 대해 알아보자.

     

    Kerberos 사용하기

    Kerberos는 Internet Engineering Task Force (IETF) 표준으로서 전형적인 키 교환 메커니즘을 정의한다. 애플리케이션들은 Kerberos 서비스를 사용하여 사용자에게 인증을 주고 암호 키를 교환한다. Kerberos는 티켓 발상에 기인한다. 하나의 티켓은 암호 키와 몇몇 정보 조각을 래핑하는 데이터 구조일 뿐이다. 키 발급 센터(KDC)는 Kerberos 티켓을 인증 사용자에게 발급한다. KDC는 두 가지 유형의 티켓을 발행한다

    • 마스터 티켓(티켓 발행 티켓 (TGT))
    • 서비스 티켓
    KDC는 우선 TGT를 클라이언트에 발행한다. 이 클라이언트는 TGT에 여러 서비스 티켓을 요청할 수 있다. TGT와 서비스 티켓의 작동 방법을 설명해주는 다음의 키 교환 시나리오를 보자:

    1. 클라이언트가 TGT의 발행을 요청하며 KDC에 메시지를 보낸다. 이 요청은 평이한 텍스트 형식(암호화 되어있지 않음)이고 클라이언트의 유저네임이 포함되어있다. 패스워드는 포함되지 않는다.
    2. KDC는 TGT를 클라이언트에 발급한다. TGT는 암호화된 형식안에 세션 키를 포함하고 있다. 이 세션 키를 암호화하려면 KDC는 클라이언트의 패스워드에서 나온 키를 사용한다. 클라이언트만이 TGT의 암호를 해독할 수 있고 세션 키를 가져올 수 있다는 것을 의미한다. 따라서 클라이언트 애플리케이션이 TGT를 요청하기 위해 패스워드를 알 필요는 없어도 TGT를 처리하고 사용할 패스워드는 필요하다.
    3. 클라이언트가 TGT의 암호를 해독하고 여기에서 세션 키를 추출한다. 클라이언트는 서비스 티켓을 위한 요청을 작성한다. 서비스 티켓은 양방간 커뮤니케이션용으로만 가능하다. 즉 클라이언트와 그 클라이언트가 통신하기 원하는 엔터티. 어떤 누구도 이 서비스 티켓을 사용할 수 없다. 따라서 서비스 티켓을 요청하는 동안 클라이언트는 서비스 티켓으로 사용 할 서버 이름을 지정한다. 이 서버는 KDC에 이미 존재하고 있어야 한다.
    4. KDC는 서버용 서비스 티켓을 작성한다. 이 티켓은 클라이언트의 인증 데이터와 새로운 암호 키(하위 세션 키)를 포함하고 있다. KDC는 서버의 비밀 키로 서비스 티켓을 암호화한다. 오직 서버만이 서비스 티켓 암호를 해독할 수 있다.
    5. KDC는 메시지를 작성하고 이 안에 서비스 티켓을 래핑한다. KDC는 이 메시지 내부에 하위 세션 키를 복사한다. 하위 세션 키는 메시지에 두 번 포함되었다는 것을 기억하라.
    6. KDC는 2, 3 단계에서 나온 세션 키로 전체 메시지를 암호화한다. 따라서 오직 클라이언트만 메시지를 해독하고 하위 세션 키와 서비스 티켓을 추출할 수 있다. 클라이언트가 서비스 티켓 암호를 해독하지 못하면 오직 서버만이 할 수 있다. 따라서 어떤 누구도 다른 목적으로 서비스 티켓을 사용할 수 없다. 그런 다음 KDC는 메시지를 클라이언트에 보낸다.
    7. 클라이언트는 KDC에서 받은 메시지를 해독하고 메시지 내부에 있는 하위 세션 키와 서비스 티켓을 가져온다. 서비스 티켓은 서버에 보낸다.
    8. 서버는 서비스 티켓을 받고 이를 해독하여 요청 클라이언트의 인증 데이터와 하위 세션 키를 가져온다. 서버는 클라이언트의 요청을 확인하고 새로운 보안 세션이 클라이언트와 서버 사이에 만들어진다. 클라이언트와 서버 모두 같은 하위 세션 키를 마련하고 있고 서로 보안 통신을 위해 이를 사용할 수 있다.
    클라이언트는 3 단계에서 8 단계 까지 또 다른 서버 애플리케이션에 반복할 수 있다. Kerberos 서비스가 인증 데이터를 공유하는 데 사용될 수 있고 같은 클라이언트가 다른 애플리케이션에도 인증을 받을 수 있다는 것을 의미한다. 이는 SSO를 효과적으로 만든다 .

     

    Java Generic Security Services API

    ETF는 Generic Security Services API (GSS-API)를 고급 보안 API로 정의했다. 이것은 Credential성, 메시지 무결성, 보안 등의 기능을 제공한다. GSS-API는 클라이언트-서버 환경에서 쉽게 작동한다. IETF는 GSS-API를 언어 독립 방식으로 정의했다.

    자바 GSS-API는 자바 스팩 형식의 GSS-API이다. Sun은 Java Community Process를 통해 자바 GSS-API를 개발했고 레퍼런스 구현도 제공했다. 이는 JDK 1.4 버전에 번들 될 것이다. (하단 참고자료 참조).

    보다 간단히 하기 위해 GSS-API를 GSS로 통칭하겠다.

    GSS는 다른 저급 보안 서비스의 상단에 고급 추상 레이어를 제공하는 것이 목적이다. Kerberos는 GSS 추상화에서 사용할 수 있는 기술 중 하나이다. GSS 추상 레이어에서 프로그래머는 보안 메커니즘을 개발 할 수 있다. 보다 낮은 레벨에서 어떤 메커니즘이 작동하고 있는지 걱정하지 않아도 된다. 이 글에서 GSS 하에서 작동하는 저급 보안 메커니즘으로서 Kerberos의 사용법에 초점을 맞추겠다.

    GSS는 GSSName, GSSCredential, GSSContext의 개념에서 작동한다. GSSName은 이메일을 확인하기 위해 입력하는 유저네임 같이 당신을 개별적 존재로 구분한다. GSSCredential은 당신의 존재를 증명하기 위해 내보이는 어떤 것이다. 이메일 확인 시 입력하는 패스워드와 같다. Kerberos 서비스 티켓은 GSSCredential의 또 다른 예제이다. GSSContext는 보안 관련 정보(암호 키)를 캡슐화하는 보안 세션 같은 것이다. GSS 기반의 애플리케이션은 GSSContext를 사용하여 안전하게 통신한다.

     

    GSS 클라이언트/서버 애플리케이션

    이 섹션에서는 GSS 기반 보안 자바 애플리케이션의 실제 구현을 설명하겠다. 재사용 가능한 JavaBeans 컴포넌트 두 개를 개발 할 것이다. 하나의 빈은 요청 클라이언트로서 작동하여 새로운 GSS 세션의 초기화를 요청한다. 다른 빈은 서버로서 작동하여 요청을 리스닝하고 클라이언트에서 오는 요청을 수락한다. 그런 다음 보안 컨텍스트를 만들고 클라이언트와 통신한다.

    이 글에서 SSO를 설명해야하기 때문에 제 삼자에 의해 호스팅되는 애플리케이션으로 KDC를 사용하여 우리 애플리케이션을 단순하게 할 것이다. 클라이언트와 서버 모두 이 KDC를 믿고 있으며 여기에서 오는 인증 데이터를 받아들인다. 따라서 이 글에 쓰인 샘플 코드를 사용하기 위해서는 Kerberos 실행이 필요하다. 하지만 GSS 호완의 KDC를 사용할 수 있다. ("KDC 설정하기" 참조)

     

    KDC 설정하기

    GSS에서의 Kerberos를 구현할 때 특별한 KDC 구현이 필요하지 않다. 따라서 GSS 기반의 모든 코드는 GSS 호완의 KDC로 작동이 될 것이다. (하단 참고자료 참조).

    이 글의 코드를 테스트 하기위해 Microsoft의 KDC 구현을 사용했다. 이것은 Windows 2000 Server 버전 및 이후 버전에서 제공한다. 이 글에 쓰인 모든 코드가 포함되어 있는 j-gss-sso.zip 파일에는 Setup.txt 파일도 포함되어 있어 Microsoft KDC 설정에 필요한 단계를 설명하고 있다.

    Microsoft KDC는 모든 Windows 사용자들을 이 서비스의 사용자로 받아들인다. KDC가 Windows 네트워크에 등록된 모든 사용자를 위해 TGT를 발급할 수 있다는 것을 의미한다

     

    JAAS 인증 클라이언트

    일단 KDC 서비스를 실행하면 계속 진행하여 TGT를 발급하도록 KDC에게 요청할 수 있다. 요청하는 GSS 클라이언트는 KDC에게 TGT를 발급하도록 요청 할 것이다.

    작은 문제가 있다. GSS는 사용자에게서 온 유저네임-패스워드 쌍을 가져올 메소드가 없다. 따라서 GSS 애플리케이션은 다른 비 GSS 메커니즘에 의존하여 로그인 정보를 얻어야 한다. 우리는 여기서 Java Authentication and Authorization Service (JAAS)를 사용하여 요청 클라이언트가 유저네임과 패스워드를 제공하고 TGT를 얻도록 하겠다.

    Listing1에서는 GSSClient 라는 클래스를 보게 될 것이다. 이 클래스는 원격 GSS 서버와 보안 세션의 설치를 원하는 GSS 클라이언트의 기능을 나타낸다. GSSClient 구조체는 많은 매개변수를 취한다:

    1. 클라이언트 피어 이름
    2. 클라이언트 피어의 패스워드
    3. 원격 서빙(serving) 피어의 이름
    4. 원격 서빙(serving) 피어의 주소
    5. 서버의 포트
    6. Kerberos 영역 또는 도메인
    7. KDC 주소
    8. 로그인 설정 파일의 이름과 위치 경로
    9. 클라이언트 설정 이름
    main() 메소드는 간단한 애플리케이션을 시뮬레이팅하고 있다. Listing 1에 이 메소드를 추가했다. 명령행에서 이를 실행하여 이 클래스의 작동을 설명하기 위해서이다. main() 메소드는 명령행에서 매개변수 값을 읽고 GSSClient() 구조체를 호출하면서 매개변수 값을 이 구조체에 보낸다.

    GSSClient() 구조체는 다른 필드에 있는 명령행에서 오는 매개변수를 저장하고 세 개의 시스템 프로퍼티를 지정한다.
    java.security.krb5.realm 시스템 프로퍼티는 KDC 범위를 지정한다. java.security.krb5.kdc 프로퍼티는 KDC 서버의 주소를 지정한다.
    java.security.auth.login.config 프로퍼티는 로그인 설정 파일의 이름과 위치 경로를 지정한다. GSS 프레임웍은 이 속성들을 내부에서 사용 할 것이다.

    GSSClient 객체를 인스턴스화 한 후에, main() 메소드는 GSSClient.login() 메소드를 호출한다. 이 메소드는 LoginContext 객체를 인스턴스화 하는데 JAAS 프레임웍의 일부이다. LoginContext 구조체는 두 개의 매개변수를 취한다. 두 번째는 BeanCallBackHandler 클래스이다. 이 둘을 자세히 살펴보자.

     

    confName과 설정파일

    confName은 JAAS 설정의 이름을 수반한다. 아홉 번째 명령행 매개변수는 클라이언트가 인증용으로 사용할 JAAS를 설정한다. 여덟 번째 매개변수로 지정된 JAAS 설정 파일에는 한 개 이상의 클라이언트 설정이 포함되어 있다. 클라이언트는 이 중 하나를 사용할 수 있다.

    JAAS 설정은 인증에 사용될 메커니즘을 정의한다. 설정 파일은 자바 애플리케이션이 인증 로직과 독립된 인증 메커니즘을 선택할 수 있도록 한다.

    JAAS 설정은 .conf 파일로 저장된다. Listing 2 의 JAAS 설정 파일 샘플에는 두 가지 설정이 있다. GssClient 설정은 다음과 같다:

     

    GSSClient {
    com.sun.security.auth.module.Krb5LoginModule required;
    };

     

    이 JAAS 설정은 com.sun.security.auth.module.Krb5LoginModule 라는 자바 클래스 이름을 지정한다. 이 클래스는 JAAS의 Kerberos 로그인 모듈이고 GSSClient 설정은 로그인에 이것을 사용한다. 따라서 이 설정을 지정한다는 것은 인증 메커니즘으로서 Kerberos를 사용한다는 것을 의미한다.

     

    Listing 1. GSSClient

    /****
    GSSClient.java
    ****/

    import java.io.*;
    import java.util.*;
    import java.security.*;
    import org.ietf.jgss.*;
    import java.net.Socket;
    import javax.security.auth.login.*;
    import javax.security.auth.Subject;

    class GSSClient
    implements java.security.PrivilegedAction {

    //Handles callback from the JAAS framework.
    BeanCallbackHandler beanCallbackHandler = null;

    //The main object that handles all JAAS login.
    LoginContext peerLC = null;

    //Socket and streams used for communication.
    Socket socket = null;
    DataInputStream inStream;
    DataOutputStream outStream;

    //This and remote clients.
    String clientName = null;
    String serverName = null;

    //Address and port of remote server.
    String serverAddress = null;
    int serverPort;

    //The name of the client configuration.
    String confName = null;

    public static void main(String[] args) {
    if (args.length < 9) {
    System.err.println("Usage: java <options> KrberosLogin "
    + " <clientname> <password> <servername> "
    + " <serveraddress> <server port> "
    + " <realm address> <kdc address> "
    + " <name and path of conf file > <conf name ");
    System.exit(-1);
    }

    GSSClient gssClient =
    new GSSClient (args[0]/*client name*/ ,
    args[1]/*password*/,
    args[2]/*clientName*/,
    args[3]/*serveraddress*/,
    Integer.parseInt(args[4])/*serverport*/,
    args[5]/*kerberos realm name*/,
    args[6]/*kdc addres*/,
    args[7]/*name and path of conf file*/,
    args[8]/*conf name*/ );

    GSSContext context = gssClient.login();
    if (context!=null)
    {
    String response = null;
    //Checking confidentiality status of context.
    if (context.getConfState())
    {
    response = gssClient.sendMessage(context,
    "A sample message from client");
    System.out.println ("Server Response "+response);
    }//if

    try {
    gssClient.getLoginContext().logout();
    context.dispose();
    } catch (Exception e) {
    e.printStackTrace();
    }//catch

    }
    else
    System.out.println("Client authentication deined...");
    }//main

    //The GSSClient constructor only sets all the required parameters.
    public GSSClient (String clientName, String password,
    String serverName, String serverAddress,
    int serverPort, String kerberosRealm,
    String kdcAddress, String confFile, String confName)
    {
    //The beanCallbackHandler will require the name and password of the client.
    beanCallbackHandler = new BeanCallbackHandler(clientName, password);
    this.clientName = clientName;
    this.serverName = serverName;
    this.serverAddress = serverAddress;
    this.serverPort = serverPort;
    this.confName = confName;
    System.setProperty("java.security.krb5.realm", kerberosRealm);
    System.setProperty("java.security.krb5.kdc", kdcAddress);
    System.setProperty("java.security.auth.login.config", confFile);

    System.out.println(this.clientName);
    }// KerberoseLoginBean


    public GSSContext login()
    {
    try {
    peerLC = new LoginContext(confName, beanCallbackHandler);
    peerLC.login();

    socket = new Socket(serverAddress, serverPort);
    inStream = new DataInputStream(socket.getInputStream());
    outStream = new DataOutputStream(socket.getOutputStream());
    return (GSSContext) Subject.doAs( peerLC.getSubject(), this);
    }
    catch (Exception e) {
    System.out.println( ">>>> GSSClient....
    Secure Context not established.." );
    e.printStackTrace();
    return null;
    }//catch

    }//establishSecureContextWithServer

    //This is the only method in PrivilegedAction interface.
    //It receives control only in case of successful authentication of the client.
    public Object run() {

    try {
    GSSManager manager = GSSManager.getInstance();
    Oid kerberos = new Oid("1.2.840.113554.1.2.2");
    GSSName clientPeerName = manager.createName(
    //Name of the client for which we want to create this GSSName object.
    clientName ,
    //Type of GSSName. Our client is a Windows user,
    //which we can specifiy using GSSName.NT_USER_NAME property.
    GSSName.NT_USER_NAME);

    GSSName remotePeerName = manager.createName(serverName, GSSName.NT_USER_NAME);
    System.out.println (">>> GSSClient... Getting client credentials");


    GSSCredential peerCredentials = manager.createCredential(
    //The GSSName object of the client.
    clientPeerName,
    //Time for which credentials whill be valid.
    10*60,
    //Kerberos mecahnism identifier.
    kerberos,
    //The client only intiates the secure context request.
    GSSCredential.INITIATE_ONLY);

    System.out.println (">>> GSSClient...
    GSSManager creating security context");
    GSSContext peerContext = manager.createContext(remotePeerName,
    kerberos,
    peerCredentials,
    GSSContext.DEFAULT_LIFETIME);

    peerContext.requestConf(true);
    byte[] byteToken = new byte[0];

    System.out.println (">>> GSSClient...
    Sending token to server over secure context");

    while (!peerContext.isEstablished()) {
    byteToken = peerContext.initSecContext(byteToken, 0, byteToken.length);
    if (byteToken != null) {
    outStream.writeInt(byteToken.length);
    outStream.write(byteToken );
    outStream.flush();
    }//if

    if (!peerContext.isEstablished()) {
    byteToken = new byte[inStream.readInt()];
    inStream.readFully(byteToken );
    }//if
    }//while (!peerContext...)

    return peerContext;

    }//try

    catch(org.ietf.jgss.GSSException ge) {
    System.out.println (">>> GSSClient...
    GSS Exception "+ge.getMessage());
    }

    catch(java.lang.Exception e) {
    System.out.println (">>> GSSClient...
    Exception "+e.getMessage());
    }//catch
    return null;
    }//run

    //Sends a message to the remote server on an already established context.
    //It returns the reply from the remote server.
    public String sendMessage(GSSContext context, String message)
    {
    byte[] serverMessage = null;
    byte[] clientMessage = null;

    MessageProp msgProp = new MessageProp(0, true);

    try {
    System.out.println(">>> GSSClient...
    Client message is ["+message+"]");
    clientMessage = context.wrap (message.getBytes(),
    0, message.getBytes().length, msgProp);
    outStream.writeInt(clientMessage.length);
    outStream.write(clientMessage);
    outStream.flush();

    //Receiving server response and sending back to client.
    serverMessage = new byte[inStream.readInt()];
    inStream.readFully(serverMessage);
    serverMessage = context.unwrap(serverMessage,
    0, serverMessage.length, msgProp);
    System.out.println(">>> GSSClient...
    Server message is ["+serverMessage+"]");
    return new String (serverMessage);
    } catch(Exception e){
    e.printStackTrace();
    return null;
    }

    }//sendMessage

    //It returns the established login context to client.
    public LoginContext getLoginContext()
    {
    return peerLC;
    }//getloginContext

    }//GSSClient

     

    Listing 2. GSSClient와 GSSServer 용 JAAS 로그인 설정

    /****
    Login.conf
    ****/

    GSSClient{
    com.sun.security.auth.module.Krb5LoginModule required;
    };

    GSSServer{
    com.sun.security.auth.module.Krb5LoginModule required
    storeKey=true;
    };

     

    BeanCallBackHandler
    Listing 1의 클라이언트를 다시 살펴보자. LoginContext 구조체 메소드 호출과 함께 전달된 두 번째 매개변수는 인증 과정 중에 콜백을 핸들할 객체를 지정한다. Callback은 자바 애플리케이션이 인증 프로세스 중에 JAAS 구현과 인터랙팅 할 수 있도록 한다. 정상적으로 콜백 기능을 사용하여 유저네임과 패스워드를 Kerberos 인증 모듈에 전달 할 수 있다. BeanCallBackHandler 구조체 call에 있는 username과 password를 전달했다는 것에 주목하라.

    Listing 3은 BeanCallBackHandler 클래스이다. 이 클래스는 CallBackHandler 라는 인터페이스를 구현한다. 이 인터페이스는 JAAS 프레임웍의 일부이고 단 하나의 메소드인 handle()을 포함하고 있다.

     

    Listing 3. JAAS 프레임웍에서 콜백 핸들링하기

    /****
    BeanCallbackHandler.java
    ****/

    import java.io.*;
    import java.security.*;
    import javax.security.auth.*;
    import javax.security.auth.callback.*;

    public class BeanCallbackHandler implements CallbackHandler {

    // Store username and password.
    String name = null;
    String password = null;

    public BeanCallbackHandler(String name, String password)
    {
    this.name = name;
    this.password = password;
    }//BeanCallbackHandler

    public void handle (Callback[] callbacks) throws
    UnsupportedCallbackException, IOException
    {
    for(int i=0; i<callbacks.length; i++) {
    Callback callBack = callbacks[i];

    // Handles username callback.
    if (callBack instanceof NameCallback) {
    NameCallback nameCallback = (NameCallback)callBack;
    nameCallback.setName(name);

    // Handles password callback.
    } else if (callBack instanceof PasswordCallback) {
    PasswordCallback passwordCallback =
    (PasswordCallback)callBack;
    passwordCallback.setPassword(password.toCharArray());

    } else {
    throw new UnsupportedCallbackException(callBack,
    "Call back not supported");
    }//else
    }//for

    }//handle

    }//BeanCallbackHandler

     

    CallBackHandler 객체의 handle() 메소드는 인증이 이루어지는 동안 제어를 자동으로 받는다.

    JAAS 프레임웍은 CallBack 객체의 어레이를 CallBackHandler 인스턴스의 handle() 메소드로 전달한다. CallBack 객체의 어레이에는 다른 유형의 콜백 객체들이 포함되어 있다. 하지만 여기에서는 두 가지 유형(NameCallBack과 PasswordCallBack)을 중심으로 설명하겠다.

    NameCallBack 객체는 JAAS 프레임웍에 username을 제공하는데 사용된다. PasswordCallBack은 인증 동안 password를 수반한다. 핸들 메소드(Listing 3)내부에서 NameCallBack 객체의 setName() 메소드를, PasswordCallBack의 setPassword() 메소드를 호출했다.

    LoginContext 구조체 호출에 따르는 두 개의 매개변수에 대한 위 논의를 요약해보면 사용자 인증에 필요한 LoginContext 객체에 모든 정보를 제공해 줄 수 있다. 따라서 Listing 1의 다음 단계는 LoginContext.login() 메소드를 호출한다. 이는 실제 로그인 프로세스를 수행할 것이다.

    인증 프로세스 중에 무엇인가 잘못된다면-예를 들어, password가 정확하지 않다거나-javax.security.auth.login.LoginException이 던져진다. 로그인 메소드 호출의 결과로 어떤 예외도 없다면 인증 프로세스가 성공했다는 것으로 간주할 수 있다.

    Kerberos 로그인을 사용하고 있기 때문에 JAAS 프레임웍은 내부적으로 KDC와의 모든 통신을 관리하고 Kerberos TGT를 보내면서 고급의 사용이 편리한 JAAS 인터페이스 뒤에 모든 기술적 상세들을 숨긴다.

    성공적인 인증은 LoginContext 객체 안에 Kerberos TGT를 로딩하게 된다. LoginContext 클래스의 getSubject() 메소드를 호출할 수 있다. 이것은 Subject라는 클래스 인스턴스를 리턴한다. Subject 인스턴스는 TGT를 래핑한다.

    이 Subject 클래스를 사용하여 우리가 로그인 했던 액션을 수행할 것이다. 보안 GSS 콘텍스트를 설치하는 것이다. 인증이 성공한 후 필요한 액션을 호출하는 방법을 보자.

    Subject 클래스에는 doAs()라는 정적 메소드가 포함되어 있다. 이것은 두 개의 매개변수를 갖는다. Listing 1의 Subject.doAs() 메소드 호출을 보자. 첫 번째 매개변수 값은 Subject 인스턴스로서 성공적인 인증 후에 획득한 것이다. doAs() 메소드는 인증된 Subject를 사용하여 권한 결정을 내린다. 이 Subject가 주어진 작동을 호출할 권한을 받았는지를 판단하는데 사용하는 것이다.

    지금까지 Subject 클래스는 TGT를 보내는데에만 사용했다. 따라서 GSSClient에 대한 권한 정책을 지정하지 않았다. 어떤 사용자라도 이 클라이언트를 실행할 수 있다. GSSClient는 주어진 작동을 실행할 때 보안 권한을 요구하지 않는다. 하지만 애플릿 같은 웹 클라이언트는 엄격한 보안 콘텍스트 하에서 실행된다. Setup.txt에는 애플릿 기반의 GSS 클라이언트를 위한 권한 정책을 작성하는 지침이 포함되어 있다.

    doAs() 메소드 호출의 두 번째 매개변수 값인 this는 GSSClient 객체(Listing 1)를 지정한다. 이 매개변수는 PriviledgedAction 인터페이스를 노출하는 객체를 기대한다. GSSClient는 그 PriviledgedAction 인터페이스를 구현한다. 하나의 클래스에 모든 클라이언트측 코드를 조합했지만 PriviledgedAction 인터페이스를 구현하는 개별 클래스를 가질 수 있다. 원한다면 말이다. 만일 그렇게 한다면 그 객체를 인스턴스화 하고 doAs() 메소드 호출과 함께 두 번째 매개변수 값으로서 이를 전달한다.

    PriviledgedAction 인터페이스에는 단 하나의 메소드 run()이 포함되어 있다. 권한 정책이 Subject로 하여금 GSSClient 클래스의 run() 메소드에 액세스 할 수 있도록 한다면 그 메소드는 개별 쓰레드 실행에서 제어를 받는다. run() 메소드가 제어를 받으면 보안 콘텍스트(TGT)가 따라온다. GSS 로직은 자동으로 그 보안 콘텍스트를 사용하고 TGT를 보낸다.

     

    GSS 클라이언트 디자인

    Listing 1의 run() 메소드에서 다음 단계를 수행하여 GSS 세션을 만들어야 한다.

    1. GSSManager를 인스턴스화 한다. GSSManager 클래스의 getInstance() 정적 메소드를 호출했던 Listing 1을 주목하라. 이것은 GSSManager 객체를 리턴한다. 이 GSSManager 객체는 적어도 Kerberos 메커니즘을 지원하고 그 밖에 다른 메커니즘도 지원할 것이다. GSSManager 클래스에는 GSS 애플리케이션이 다른 보안 메커니즘을 정의하기 위해 호출할 수 있는 메소드들이 포함되어 있다. 지금은 Kerberos 메커니즘을 중심으로 설명하는 것이니 만큼 getInstance() 메소드를 호출하여 Kerberos 메커니즘을 사용한다. Listing 1의 GSSManager 객체를 인스턴스화 한 후에 kerberos라는 Oid (Object ID) 객체를 인스턴스화 했다. 이것은 Kerberos 메커니즘을 확인한다. ."
    2. GSSName 객체를 만든다. 이것은 GSS 엔터티를 나타낸다. 투웨이 통신을 하는 동안 GSS 엔터티를 통신 피어로 생각할 수 있다. 따라서 두 개의 GSSName 객체를 만드는 것이다. 하나는 요청 클라이언트 피어(clientPeerName)용이고 또 다른 하나는 원격 피어(remotePeerName)용이다.
    3. Credential 세트를 만든다. GSS는 일반적인 보안 메커니즘이다. 따라서 기저의 기술에 의존하여 이러한 Credential을 만든다. Kerberos를 사용하고 있으므로 Kerberos 티켓은 실제 Credential이다. GSSCredential 객체를 얻으려면 GSSManager 클래스의 createCredential() 메소드를 사용한다. createCredential() 메소드는 GSSCredential 인터페이스를 노출하는 객체를 리턴한다.
    4. 보안 GSS 콘텍스트를 만든다. 이것은 두 개의 통신 피어 간 보안 통신을 확립하는데 사용된다. GSSManager의 createContext() 메소드는 GSSContext 인터페이스의 인스턴스를 만들어 리턴한다. GSSContext 객체는 실제 보안 콘텍스트를 래핑한다. Listing 1에서 GSSName과 GSSCredential 객체를 전달했다는 것에 주목하라.
    보안 콘텍스트를 래핑하는 GSSContext 객체를 가졌지만 콘텍스트 그 자체는 아직 설치되지 않았다. GSSContext 객체를 얻은 후 요청 피어가 이것의 requestConf() 메소드를 호출 할 것이다. 이 메소드는 애플리케이션이 기밀성과 데이터 무결성을 요청하게 하여 원격으로 보내는 모든 데이터가 암호화된 형식이 되도록 한다.

    Listing 1에서 requestConf() 메소드를 호출 한 후에 byteToken이라는 바이트의 어레이를 선언했고 이를 제로 사이즈 바이트로 인스턴스화 했다. byteToken 어레이는 GSS 클라이언트가 서버에서 송수신하는 데이터 바이트를 갖고있게된다.

    GSSContext 인터페이스의 initSecContext() 메소드를 while 루프에서 반복적으로 호출한다. 이 메소드는 실제 바이트 교환을 수행하여 요청 피어와 서빙 피어 간 보안 콘텍스트를 확립한다.

    while(!peerContext.isEstablished()) 블록(Listing 1)은 실제로 GSS 클라이언트와 서버 간 투웨이 통신을 수행한다. 이 블록은 보안 콘텍스트가 설치되었을 때에만 종료된다.

    while 루프가 첫번째로 실행될 때 byteToken 어레이에는 데이터가 없다. peerContext.isEstablished() 메소드는 false를 리턴할 것이다. 보안 콘텍스트가 아직 설치되지 않았기 때문이다.

    while 루프 내부에서 우리가 수행하는 첫 번째 일은 byteToken 어레이상에서 initSecContext() 메소드를 전달하는 것이다. 이 메소드는 두 가지의 일을 한다. 클라이언트가 서버에 보내는 바이트를 만들어내고 서버에서 오는 바이트를 받아들인다. 바이트 교환은 GSS 콘텍스트가 확립될 때 까지 계속된다.

    처음에 initSecContext() 메소드를 호출 할 때 전달할 바이트가 없다. 따라서 비어있는 byteToken 어레이에서 첫 번째 호출용 메소드에 전달한다. initSecContext() 메소드는 몇몇 바이트를 리턴하는데 이것은 같은 byteToken 어레이에 저장되었다. 그 다음 byteToken을 아웃풋 스트림에 작성하고 스트림을 플러시 하여 byteToken 어레이가 원격 서버로 보내지도록 한다.

    원격 서버에 보내진 바이트에 대한 응답으로 원격 서버는 어떤 것을 보낼것으로 기대할 수 있다. 따라서 우리는 인풋 스트림에서 바이트를 읽고 같은 byteToken 어레이에 이 바이트를 저장하고 byteToken 어레이를 다시 initSecContext() 메소드에 보낸다. 이 메소드는 다시 바이트 어레이를 리턴한다. 이러한 바이트 교환은 while 루프 내부에서 보안 콘텍스트가 확립되고 peerContext.isEstablished() 메소드가 true를 리턴할 때 까지 지속된다.

    보안 콘텍스트의 설치가 의미하는 것은 적절한 Kerberos 키들이 클라이언트와 서버 양측에서 사용가능한 상태가 된다는 것을 의미한다. 양측에서 이 키들을 사용하여 보안 통신에 쓴다. 보안 콘텍스트가 성립되면 GSSContext 객체를 리턴한다.

     

    GSS 콘텍스트 사용하기

    GSSClient 클래스의 main() 메소드에서 GSSContext 객체를 사용하는 방법을 살펴보겠다. login() 메소드를 호출한 후 login() 메소드가 리턴한 GSSContext 이 null인지를 확인한다. null이 아니라면 보안 콘텍스트가 원격 서버와의 보안 통신에 사용될 수 있다.

    main() 메소드는 원격 서버가 기밀성과 메시지 무결성이라는 클라이언트 요청에 합당한지를 점검한다. 서버가 요청에 합당하면 GSSContext 클래스의 getConfState() 메소드는 true를 리턴한다.

    main() 메소드는 원격 메소드로 보내는 데이터가 무엇이든 보낼 수 있다. sendMessage() 헬퍼 메소드를 작성하여 데이터를 서버에 보냈다. GSSContext 클래스의 wrap() 메소드는 데이터의 바이트 어레이를 받아들이고 바이트 어레이를 리턴한다. sendMessage() 메소드는 플레인 텍스트 데이터를 wrap() 메소드에 보내고 응답으로 암호화된 바이트 어레이를 받는다. 아웃풋 스트림 상에서 바이트 어레이를 작성하여 암호화된 바이트 어레이를 원격 서버로 보낼 수 있다.

    sendMessage() 메소드는 서버에서 오는 인커밍 데이터를 리스닝한다. 서버에서 데이터를 받으면 인커밍 데이터를 GSSContext 클래스의 unwrap() 메소드에 보낼 수 있다. 이것은 평이한 텍스트 형식의 데이터를 리턴한다

     

    GSS 서버 애플리케이션

    지금까지 GSS 클라이언트 애플리케이션이 작동 방법을 보았다. 이제 이것과 인터랙팅 할 서버를 구현해본다. Listing 4는 GSSServer 클래스용 코드이다. GSSServer의 startServer() 메소드는 GSSClient 클래스의 login() 메소드를 설명하면서 거론되었던 것과 같은 기능을 수행한다.

    GSSServer 클래스의 run() 메소드 내부에서 GSSManager와 GSSName 객체를 만들었다. 지금까지 클라이언트측 코드와 서버측 코드 사이에 차이점이 거의 없었다. 하지만 좀더 자세히 보면 서버는 단 하나의 GSSName 객체를 만든다는 것을 알 수 있다. 이것은 서버를 나타낸다. GSSName을 만든 후에 이 서버는 createCredential() 메소드를 호출하여 GSSCredential 객체에 credentials를 로딩한다.

    다음 단계는 GSS 콘텍스트를 만들기 위해 createContext() 객체를 호출하는 것이다. createContext() 메소드 호출은 GSS 클라이언트 애플리케이션에서 이루어진 createContext() 호출과는 다르다. 지금의 createContext() 메소드는 단 하나의 매개변수의 서버의 credential을 갖는다. 이 서버측 콘텍스트가 양측 사이에 있지 않다는 것을 의미한다.

    다음에는 통신용 인풋과 아웃풋 스트림을 만든다. 그런 다음 보안 콘텍스트가 설치될 때까지 계속 루핑 할 while 루프로 들어간다. 이 루프 안에서 요청 클라이언트를 기다려 연결 구축 요청을 보낸다. while 루프 내부의 인풋 스트림 상에서 데이터를 받으면 데이터를 바이트 어레이로 읽고 바이트 어레이 토큰을 GSSContext 클래스의 acceptSecContext() 메소드에 제공한다. acceptSecContext() 메소드는 데이터 바이트를 리턴한다. 이것은 아웃풋 스트림으로 되돌아간다.

    GSSContext의 initSecContext()와 acceptSecContext() 메소드는 결합하여 작동한다. GSS 클라이언트 애플리케이션을 설명하면서 initSecContext() 메소드의 사용법을 설명했다. initSecContext() 메소드는 GSS 클라이언트가 GSS 서버 애플리케이션으로 보내는 초기 바이트를 만들어낸다. acceptSecContext() 메소드는 이러한 인커밍 바이트를 받아들이고 이것의 바이트 어레이를 만들어낸다. 이것을 클라이언트로 보낸다. 이러한 바이트 교환은 보안 GSS 콘텍스트가 구축될 때 까지 지속된다.

    GSS는 모든 통신을 바이트 어레이 토큰으로서 핸들한다. 클라이언트에서 서버로 바이트 어레이를 나르기위해 어떤 유형의 전송 서비스를 사용할 수 있다. GSS는 데이터 전송에 사용되는 것에는 관심이 없다.

    보안 세션의 구축 과정은 요청 클라이언트의 인증으로 끝을 맺는다. GSSContext 클래스의 getSrcName() 메소드를 호출하여 인증된 클라이언트의 GSSName을 보낼 수 있다. 반면 GSSContext 클래스의 getTargName() 메소드는 원격 클라이언트의 요청을 수락한 서버의 GSSName을 리턴한다.

    while (!context.isEstablished()) 루프가 리턴한 후에(Listing 4) run() 메소드는 클라이언트로 부터 통신을 기다린다. 인커밍 데이터를 계속해서 리스닝하고 인커밍 바이트 스트링을 받게되면 GSSContext 클래스의 unwrap() 메소드를 통해 스트링을 보낸다. unwrap() 메소드는 클라이언트에서 온 평이한 텍스트 형식의 메시지를 리턴한다.

     

    Listing 4. GSSServer

    /****
    GSSServer.java
    ****/

    import org.ietf.jgss.*;
    import java.io.*;
    import java.net.Socket;
    import java.net.ServerSocket;

    import java.util.*;
    import java.security.*;
    import javax.security.auth.callback.*;
    import javax.security.auth.login.*;
    import javax.security.auth.Subject;
    import com.sun.security.auth.callback.TextCallbackHandler;

    public class GSSServer implements java.security.PrivilegedAction {

    //Handles callback from the JAAS framework.
    BeanCallbackHandler beanCallbackHandler = null;

    //The main object that handles all JAAS login.
    LoginContext serverLC = null;

    //The context for secure communication with client.
    GSSContext serverGSSContext = null;

    //Socket and streams used for communication.
    ServerSocket serverSocket = null;
    DataInputStream inStream = null;
    DataOutputStream outStream = null;

    //Name and port of server.
    String serverName = null;
    int serverPort;

    //Configuration file and the name of the client configuration.
    String confFile = null;
    String confName = null;

    public static void main(String[] args) throws IOException, GSSException
    {

    if (args.length < 6) {
    System.err.println("Usage: java <options>
    RemoteServer <server name> <port>
    <relam> <kdc> <conf file> <conf name>");
    System.exit(-1);
    }

    GSSContext context = null;
    GSSServer server = new GSSServer (args[0]/*serverName*/,
    args[1]/*password*/,
    Integer.parseInt(args[2])/*port*/,
    args[3]/*kerberos realm name*/,
    args[4]/*kdc address*/,
    args[5]/*confFile*/,
    args[6]/*confName*/);

    //Starting the server.
    server.startServer();

    }//main

    //GSSServer constructor
    public GSSServer (String serverName, String password,
    int serverPort, String kerberosRealm,
    String kdcAddress, String confFile, String confName)
    {
    beanCallbackHandler = new BeanCallbackHandler(serverName, password);
    this.serverName = serverName;
    this.serverPort = serverPort;
    this.confName = confName;
    System.setProperty("java.security.krb5.realm", kerberosRealm);
    System.setProperty("java.security.krb5.kdc", kdcAddress);
    System.setProperty("java.security.auth.login.config", confFile);

    }//GSSServer

    public boolean startServer()
    {
    try {
    serverLC = new LoginContext(confName, beanCallbackHandler);
    serverLC.login();
    Subject.doAs(serverLC.getSubject(), this);
    return true;
    } catch (Exception e) {
    System.out.println(">>> GSSServer...
    Secure Context not established.." );
    return false;
    }//catch

    }//start

    public Object run()
    {
    try {
    serverSocket = new ServerSocket(serverPort);
    GSSManager manager = GSSManager.getInstance();
    Oid kerberos = new Oid("1.2.840.113554.1.2.2");

    System.out.println(">>> GSSServer starts....
    Waiting for incoming connection");

    GSSName serverGSSName = manager.createName(serverName,null);
    GSSCredential serverGSSCreds = manager.createCredential(serverGSSName,
    GSSCredential.INDEFINITE_LIFETIME,
    kerberos,
    //The server accepts secure context request.
    GSSCredential.ACCEPT_ONLY);

    serverGSSContext = manager.createContext(serverGSSCreds);

    Socket clientSocket = serverSocket.accept();
    inStream = new DataInputStream(clientSocket.getInputStream());
    outStream = new DataOutputStream(clientSocket.getOutputStream());

    byte[] byteToken = null;

    while (!serverGSSContext.isEstablished())
    {
    byteToken = new byte[inStream.readInt()];
    inStream.readFully(byteToken);
    byteToken = serverGSSContext.acceptSecContext (byteToken,
    0, byteToken.length);

    if (byteToken!= null)
    {
    outStream.writeInt(byteToken.length);
    outStream.write(byteToken);
    outStream.flush();
    }//if
    }//while (!context.isEstablished())

    String clientName =serverGSSContext.getTargName().toString();
    String serverName = serverGSSContext.getSrcName().toString();
    MessageProp msgProp = new MessageProp(0, false);

    byteToken = new byte[inStream.readInt()];
    inStream.readFully(byteToken);

    //Unwrapping and verifiying the received message.
    byte[] message = serverGSSContext.unwrap(byteToken, 0,
    byteToken.length, msgProp);

    System.out.println(">>> GSSServer Message
    ["+new String(message)+" ] received");

    //Wrapping the response message.
    message = new String(">>> GSSServer Secure Context establish between
    ["+clientName+"] and ["+serverName+"]").getBytes();

    message = serverGSSContext.wrap(message, 0,
    message.length, msgProp);
    outStream.writeInt(message.length);
    outStream.write(message);
    outStream.flush();
    System.out.println(">>> GSSServer Message
    ["+new String(message)+"] sent");

    //Disposing and closing client and server sockets.
    serverGSSContext.dispose();
    clientSocket.close();
    serverSocket.close();
    System.out.println(">>> GSSServer shutdown.... ");
    }//try
    catch(java.lang.Exception e){
    e.printStackTrace();
    }

    return null;

    }//run

    }//GSSServer

     

    브라우저 속의 GSS

    Listing 5는 애플릿이 Listing 1의 GSS 클라이언트를 사용하여 Listing 4의 GSS 서버와의 보안 통신을 구축하는 방법이 나와있다. 이 애플릿은 HTML 페이지에서 실행될 것이다. (Listing 6):

     

    Listing 5. GSSClientApplet

    /****
    GSSClientApplet.java
    ****/

    import java.awt.*;
    import java.awt.event.*;
    import java.applet.Applet;

    import org.ietf.jgss.*;

    public class GSSClientApplet extends Applet {

    //Instance of GSSClient bean and GSS context.
    GSSClient gssClient = null;
    GSSContext context = null;

    //Labels for user input fields.
    Label lblUserName = new Label ("EMarketplace ID :");
    Label lblPassword = new Label ("Password :");

    //Text input fileds for user name and password.
    TextField tfUserName = new TextField (12);
    TextField tfPassword = new TextField (12);

    //Buttons representing emarketplace partners.
    Button buttonPartner1 = new Button(" Login to Partner1 ");
    Button buttonPartner2 = new Button(" Login to Partner2 ");
    Button buttonPartner3 = new Button(" Login to Partner3 ");

    Color bgColor = new Color (204,204,255);

    //TextArea to show login progress.
    TextArea taResponse = null;

    //GSS related parameters.
    String remotePeer = null;
    String kerberosRealm = null;
    String kdcAddress = null;
    String addressOfRemotePeer = null;
    int portOfRemotePeer;
    String confName = null;
    String confFile = null;

    // Intializes applet with appropiate layout and listners.
    public void init()
    {
    setLayout(new FlowLayout(FlowLayout.CENTER));
    add(lblUserName);
    add(tfUserName);
    add(lblPassword);
    add(tfPassword);

    buttonPartner1.setBackground(bgColor);
    buttonPartner2.setBackground(bgColor);
    buttonPartner3.setBackground(bgColor);

    kerberosRealm = "EMARKET.LOCAL";
    kdcAddress = "pak.emarket.local:88";
    addressOfRemotePeer = "pak";

    confFile = "C:/login.conf";
    confName = "GSSClient";

    add(buttonPartner1);
    buttonPartner1.addActionListener ( new ActionListener() {
    public void actionPerformed(ActionEvent evt)
    {
    remotePeer = "partner1";
    portOfRemotePeer = 1080;
    login();
    }
    }//ActionListener
    );

    add(buttonPartner2);
    buttonPartner2.addActionListener ( new ActionListener() {
    public void actionPerformed(ActionEvent evt)
    {
    remotePeer = "partner2";
    portOfRemotePeer = 1082;
    login();
    }//action performed
    }//ActionListener
    );

    add(buttonPartner3);
    buttonPartner3.addActionListener ( new ActionListener() {
    public void actionPerformed(ActionEvent evt)
    {
    remotePeer = "partner3";
    portOfRemotePeer = 1084;
    login();
    }//action performed
    }//ActionListener
    );

    taResponse = new TextArea("[Output Window]....\n\r",12,58);
    taResponse.setBackground(Color.white);
    add (taResponse);

    }//init()

    private void login()
    {
    try {

    if (tfUserName.getText().equals("") @amp;@amp;
    tfPassword.getText().equals(""))
    taResponse.append("Please use your E-Commerce site Id to login..\n\r");
    else
    {
    gssClient = new GSSClient (
    tfUserName.getText()+"@"+kerberosRealm,
    tfPassword.getText(),
    remotePeer,
    addressOfRemotePeer,
    portOfRemotePeer,
    kerberosRealm,
    kdcAddress,
    confFile,
    confName);

    taResponse.append(tfUserName.getText()+" being logged in..\n\r");
    context = gssClient.login();
    if (context!=null)
    {
    //Checking confidentiality status of context.
    if (context.getConfState())
    {
    String message = new String ("A sample message from client");
    taResponse.append("You are successfully logged in.. \n\r");
    taResponse.append("Sending ["+message+"] to server \n\r");
    String response = gssClient.sendMessage(context, message);
    taResponse.append("Server response ... "+response+"\n\r");
    }
    else
    taResponse.append("Context confidentiality failed...\n\r");

    //Closing Login and GSS contexts.
    try {
    gssClient.getLoginContext().logout();
    context.dispose();
    } catch (Exception e) {
    e.printStackTrace();
    }//catch
    }
    else
    taResponse.append("Context establishment failed...\n\r");

    }//else

    }//try
    catch (Exception e) {
    taResponse.append("Exception..."+e.getMessage()+"\n\r");
    }//catch

    }//login

    }//GSSClientApplet

     

    Listing 6. GSS 애플릿을 사용하는 HTML 페이지

    <!--
    E-Commerce Login.html
    -->

    <HTML>
    <HEAD>
    <TITLE>E-Commerce Login... </TITLE>
    </HEAD>
    <BODY>
    <p align="center">
    <table bgcolor="Gray">
    <tr>
    <td align="center">
    <b>E-Commerce Site Login Page </b>
    </td>
    </tr>
    <tr>
    <td>
    <Applet
    CODE="GSSClientApplet.class"
    archive="GSSClientApplet.jar"
    name="GSSClientApplet"
    width="500" height="280">
    </Applet>
    </td>
    </tr>
    </table>
    </p>
    </BODY>
    </HTML>

     

    이 애플릿이 e-커머스 웹 사이트의 메인 페이지에서 실행된다고 생각해보자. 그림 1은 실행 모습을 나타낸 것이다. 두 개의 텍스트 엔트리 필드, 버튼 세 개, 하나의 텍스트 영역이 있다. 세 개의 버튼 각각은 e-커머스 웹 사이트의 파트너의 서버측 구현에 상응한다.

    그림 1. GSS 애플릿 사용



    e-커머스 웹 사이트 고객은 어떤 사이트 파트너라도 인증받을 수 있다. 애플릿의 텍스트 필드에 유저네임과 패스워드를 입력하고 인증을 원하는 파트너 사이트에 해당하는 Login 버튼을 누른다. 이 버튼의 이벤트 핸들러는 GSSClient 구조체에 필요한 매개변수를 제공한다. 나머지 작업은 GSS 클라이언트가 할 일이고 이것은 이미 설명했다.

     

    참고자료

    - developerWorks worldwide 사이트에서 이 기사에 관한 영어원문
    - 소스코드 다운로드.
    - RFC 1510.
    - RFC 1508 & RFC 1964.
    - GSS page: Sun Web site.
    - KDC implementation: MIT.
    - CSG group & Heimdal.
    - "Enhance Java GSS-API with a login interface using JAAS" : Thomas Owusu (developerWorks, November 2001).
    - "Java security, Part 2: Authentication and authorization" : Brad Rubin (developerWorks,July 2002).
    - RFC 2025.
    - developerWorks Java technology zone.

     

    출처 : Tong - 미니아빠님의 개발자료실통


  • '참고자료 > SSO' 카테고리의 다른 글

    SSO(Single Sign On)  (0) 2009.02.13
    Open Source SSO 에 대한 핵심 정리 파워포인트 자료  (0) 2009.02.13
    DB를 이용한 SSO 구현 방법론  (0) 2009.02.13
    Single Sign On  (0) 2009.02.13
    SSO 적용 모델  (0) 2009.02.13

    + Recent posts